Итак, свершилось: кусочек компилятора был переписан на обероне и скомпилирован самим компилятором. Надо сказать, что в этом что-то есть
Типа непосредственного прикосновения к вечной проблеме курицы и яйца.
Код приведен в самом конце. Текущие впечатления от кодирования:
- В отсутствие методов запись "Stream.pos(stream)" конечно многословнее и воспринимается хуже, чем "stream.pos()".
- Дублирование в конце имени процедуры - жестокое и беспощадное. Программер должен страдать. Особенно если захочет переименовать. Смысла - 0. Если уж боремся за читабельность, то лучше запретить процедуры длиннее 10 строк...
- Точка с запятой после RETURN. Точнее требование ее отсутствия. Вот уж действительно мелочь, но вот чисто с эргономической точки зрения напрягает страшно. Удобство принесенное в жертву формализму.
- Тяжелый синтаксис. Даже если постараться не смотреть на КАПС. Т.е. я конечно в курсе незабвенного "синтаксического оверхеда", но вот в случае тривиальных процедур - обероновский код выглядит если не многословным, то многобуквенным. И даже "int" vs "INTEGER" начинает напрягать. Т.е. пока пишешь "int" в каком-нибудь С++ это кажется и не таким важным. Но вот пописав "INTGER" начинаешь ценить более короткий вариант.
MODULE Stream;
IMPORT JsString;
TYPE
Type = POINTER TO RECORD
s: JsString.Type;
pos: INTEGER
END;
ReaderProc = PROCEDURE(c: CHAR): BOOLEAN;
PROCEDURE make*(text: JsString.Type): Type;
VAR result: Type;
BEGIN
NEW(result);
result.s := text;
RETURN result
END make;
PROCEDURE eof*(self: Type): BOOLEAN;
RETURN self.pos = JsString.len(self.s)
END eof;
PROCEDURE pos*(self: Type): INTEGER;
RETURN self.pos
END pos;
PROCEDURE setPos*(self: Type; pos: INTEGER);
BEGIN
ASSERT(pos <= JsString.len(self.s));
self.pos := pos
END setPos;
PROCEDURE next*(self: Type; n: INTEGER);
BEGIN
ASSERT(self.pos + n <= JsString.len(self.s));
self.pos := self.pos + n;
END next;
PROCEDURE peekChar*(self: Type): CHAR;
BEGIN
ASSERT(~eof(self));
RETURN JsString.at(self.s, self.pos)
END peekChar;
PROCEDURE getChar*(self: Type): CHAR;
VAR result: CHAR;
BEGIN
ASSERT(~eof(self));
result := JsString.at(self.s, self.pos);
INC(self.pos);
RETURN result
END getChar;
PROCEDURE peekStr*(self: Type; len: INTEGER): JsString.Type;
VAR max: INTEGER;
BEGIN
max := JsString.len(self.s) - self.pos;
IF len > max THEN
len := max;
END
RETURN JsString.substr(self.s, self.pos, len)
END peekStr;
PROCEDURE read*(self: Type; f: ReaderProc): BOOLEAN;
BEGIN
WHILE ~eof(self) & f(peekChar(self)) DO
next(self, 1);
END
RETURN ~eof(self)
END read;
PROCEDURE lineNumber*(self: Type): INTEGER;
VAR
line: INTEGER;
lastPos: INTEGER;
BEGIN
lastPos := JsString.indexOf(self.s, 0DX);
WHILE (lastPos # -1) & (lastPos < self.pos) DO
INC(line);
lastPos := JsString.indexOfFrom(self.s, 0DX, lastPos + 1);
END;
RETURN line + 1
END lineNumber;
END Stream.