public static TYPE parseTypeSpecifier(iSCOPE context, out bool ref_val, out bool conc, out Span final) { TYPE type = null; bool opt = false; ref_val = false; conc = false; Token token = get(); Token begin = token; if (token.code == TokenCode.Question) { forget(); token = get(); opt = true; } switch (token.code) { case TokenCode.As: forget(); EXPRESSION example = PRIMARY.parse(null, context); type = example.type; if (type != null) { type.setSpan(begin.span, example.span); if (type is UNIT_REF) { (type as UNIT_REF).setSpecs(opt, true); } } final = example.span; break; case TokenCode.Ref: ref_val = true; forget(); goto ParseType; case TokenCode.Concurrent: conc = true; forget(); goto ParseType; case TokenCode.Val: forget(); goto ParseType; case TokenCode.LParen: // Seems to a tuple type type = TUPLE_TYPE.parse(context); context.add(type); final = type.span; break; default: // forget(); ParseType: UNIT_REF unitRef = UNIT_REF.parse(null, opt, context); if (unitRef == null) /* An error was detected earlier */ { final = null; return(null); } final = unitRef.span; token = get(); return(unitRef); } return(type); }
/// <summary> /// /// </summary> /// <returns></returns> public static void parse(bool hidden, bool final, Token start, iSCOPE context) { Debug.Indent(); Debug.WriteLine("Entering CONSTANT.parse"); CONSTANT constant = new CONSTANT(); // 'const' and 'is' keywords were already parsed Token token = get(); if (token.code == TokenCode.End) { forget(); goto FinalActions; } // empty list while (true) { EXPRESSION left = EXPRESSION.parse(null, context); token = get(); if (token.code == TokenCode.DotDot) // range { forget(); EXPRESSION right = EXPRESSION.parse(null, context); BINARY range = new BINARY(left, right); range.setSpan(left.span, right.span); range.parent = constant; constant.constants.Add(range); } else // single expression { left.parent = constant; constant.constants.Add(left); } token = get(); if (token.code == TokenCode.Comma) { forget(); continue; } if (token.code == TokenCode.End) { forget(); break; } else { error(token, "syntax-error"); break; } } FinalActions: constant.setSpecs(hidden, final); context.add(constant); constant.parent = context.self; constant.setSpan(start, token); Debug.WriteLine("Exiting CONSTANT.parse"); Debug.Unindent(); }
/// <summary> /// /// </summary> /// <syntax> /// Try : try /// StatementList /// catch ( [ Identifier : ] UnitType ) /// [ StatementList ] /// { catch ( [ Identifier : ] UnitType ) /// [ StatementList ] /// } /// [ else [ StatementsList ] ] /// end /// </syntax> /// <returns></returns> public static void parse(iSCOPE context) { Token token = get(); Token begin = token; if (token.code != TokenCode.Try) // Compiler error { } forget(); TRY result = new TRY(); Context.enter(result); BODY.parse(TokenCode.Catch, TokenCode.ERROR, TokenCode.ERROR, result); while (true) { token = get(); if (token.code != TokenCode.Catch) { break; } CATCH.parse(result); } token = get(); if (token.code == TokenCode.Else) { forget(); BODY.parse(TokenCode.End, TokenCode.ERROR, TokenCode.ERROR, context); } token = get(); if (token.code != TokenCode.End) // Syntax error { } forget(); result.setSpan(begin, token); context.add(result); Context.exit(); }
/// <summary> /// /// </summary> /// <syntax> /// Loop : while BooleanExpression /// loop /// [ invariant PredicateList ] /// [ StatementList ] /// [ variant PredicateList ] /// end [ loop ] /// /// | loop /// [ invariant PredicateList ] /// [ StatementList ] /// [ variant PredicateList ] /// [ while BooleanExpression ] /// end [ loop ] /// </syntax> /// <returns></returns> public static void parse(Token id, iSCOPE context) { Debug.Indent(); Debug.WriteLine("Entering LOOP.parse"); // If id != null, then 'id' is a loop label. // ':' after label is already parsed. LOOP loop = new LOOP(); Context.enter(loop); Token token = get(); Token begin = token; if (token.code == TokenCode.While) { forget(); loop.prefix = true; EXPRESSION whileExpr = EXPRESSION.parse(null, context); token = get(); if (token.code == TokenCode.Loop) { forget(); loop.addw(whileExpr); whileExpr.parent = loop; } else // Syntax error { error(token, "no-loop"); } token = get(); if (token.code == TokenCode.Invariant) { forget(); parseInvariant(loop); } BODY body = new BODY(); body.parent = loop; loop.body = body; Context.enter(body); token = get(); BODY.parse(TokenCode.End, TokenCode.Variant, TokenCode.ERROR, body); body.setSpan(token, get()); Context.exit(); token = get(); if (token.code == TokenCode.Variant) { forget(); parseVariant(loop); } } else if (token.code == TokenCode.Loop) { loop.prefix = false; forget(); token = get(); if (token.code == TokenCode.Invariant) { forget(); parseInvariant(loop); } BODY body = new BODY(); body.parent = loop; loop.body = body; Context.enter(body); token = get(); BODY.parse(TokenCode.End, TokenCode.Variant, TokenCode.While, body); body.setSpan(token, get()); Context.exit(); token = get(); if (token.code == TokenCode.Variant) { forget(); parseVariant(loop); } token = get(); if (token.code == TokenCode.While) { forget(); EXPRESSION whileExpr = EXPRESSION.parse(null, context); loop.addw(whileExpr); whileExpr.parent = loop; } } else // Compiler error { error(token, "system-bug"); } token = get(); if (token.code != TokenCode.End) // Syntax error { error(token, "no-end", "loop"); } else { forget(); token = get(); if (token.code == TokenCode.Loop) { forget(); } } if (loop != null) { loop.setSpan(begin, token); } context.add(loop); Context.exit(); Debug.WriteLine("Exiting LOOP.parse"); Debug.Unindent(); }
public static void parse(Token routineName, bool hidden, bool final, bool isOverride, int pure_safe, iSCOPE context) { ROUTINE routine = null; if (routineName.code == TokenCode.Init) { Debug.Indent(); Debug.WriteLine("Entering INITIALIZER.parse"); routine = new INITIALIZER(); goto Init; } Debug.Indent(); Debug.WriteLine("Entering ROUTINE.parse (" + routineName.image + ")"); string image = routineName.image; Token token = get(); // What's after the routine name? switch (routineName.image) { case "and": if (token.code == TokenCode.Then) { forget(); image += " then"; Span span = new Span(routineName.span, token.span); routineName = new Token(span, TokenCode.Identifier, image, new Category(CategoryCode.identifier)); } break; case "or": token = get(); if (token.code == TokenCode.Else) { forget(); image += " else"; Span span = new Span(routineName.span, token.span); routineName = new Token(span, TokenCode.Identifier, image, new Category(CategoryCode.identifier)); } break; } routine = new ROUTINE(pure_safe, isOverride, routineName); Init: routine.setSpecs(hidden, final); Context.enter(routine); if (routineName.code == TokenCode.Init) { goto Init2; } token = get(); if (token.code == TokenCode.Alias) { forget(); token = expect(TokenCode.Identifier); routine.alias = new IDENTIFIER(token.image); } if (token.code == TokenCode.LBracket) { // Generic routine forget(); while (true) { var generic = FORMAL_GENERIC.parse(context); routine.add(generic); token = get(); switch (token.code) { case TokenCode.Comma: case TokenCode.Semicolon: forget(); continue; case TokenCode.RBracket: forget(); goto Finish; default: { /* Syntax error */ break; } } } Finish: ; } Init2: token = get(); if (token.code == TokenCode.LParen) { forget(); token = get(); if (token.code == TokenCode.RParen) { // Empty parameter list forget(); goto Weiter; } while (true) { VARIABLE.parse(false, false, false, false, null, null, routine); token = get(); if (token.code == TokenCode.Comma) { forget(); continue; } if (token.code == TokenCode.Semicolon) { forget(); continue; } break; } expect(TokenCode.RParen); } Weiter: token = get(); if (token.code == TokenCode.Colon) { forget(); bool ref_val, conc; // TEMP SOLUTION Span span2; routine.type = VARIABLE.parseTypeSpecifier(routine, out ref_val, out conc, out span2); if (routine.type != null) { routine.type.parent = routine; routine.type.setSpan(span2); } } token = get(); if (token.code == TokenCode.Require) { forget(); token = get(); if (token.code == TokenCode.Else) { forget(); routine.requireElse = true; } while (true) { EXPRESSION precondition = EXPRESSION.parse(null, routine); routine.addPre(precondition); precondition.parent = routine; token = get(); if (token.code == TokenCode.Is || token.code == TokenCode.Arrow) { break; } } } if (token.code == TokenCode.Arrow) { forget(); BODY body = new BODY(); routine.routineBody = body; body.parent = routine; Context.enter(body); EXPRESSION expression = EXPRESSION.parse(null, body); RETURN ret = new RETURN(expression); expression.parent = ret; ret.setSpan(expression.span); ret.parent = body; body.add(ret); body.setSpan(ret.span); Context.exit(); } else if (token.code == TokenCode.Is) { forget(); token = get(); if (token.code == TokenCode.Abstract) { forget(); routine.isAbstract = true; } else if (token.code == TokenCode.Foreign) { forget(); routine.isForeign = true; } else { BODY body = new BODY(); body.parent = routine; routine.routineBody = body; Context.enter(body); BODY.parse(TokenCode.End, TokenCode.Ensure, TokenCode.ERROR, body); Context.exit(); } token = get(); if (token.code == TokenCode.Ensure) { forget(); token = get(); if (token.code == TokenCode.Then) { forget(); routine.ensureThen = true; } ENTITY.weAreWithinEnsure = true; while (true) { EXPRESSION postcondition = EXPRESSION.parse(null, routine); routine.addPre(postcondition); postcondition.parent = routine; token = get(); if (token.code == TokenCode.End) { forget(); break; } } ENTITY.weAreWithinEnsure = false; } else if (!routine.isAbstract && !routine.isForeign) { expect(TokenCode.End); } } token = get(); if (token.code == TokenCode.Semicolon) { forget(); } Context.exit(); context.add(routine); routine.parent = context.self; routine.setSpan(routineName, token); if (routineName.code == TokenCode.Init) { Debug.WriteLine("Exiting INITIALIZER.parse"); } else { Debug.WriteLine("Exiting ROUTINE.parse"); } Debug.Unindent(); }
public static void parse(iSCOPE context) // REWRITE!! { Token token = get(); Token begin = token; if (token.code != TokenCode.Catch) // Compiler error { } forget(); CATCH handler = new CATCH(); Context.enter(handler); token = get(); if (token.code != TokenCode.LParen) // Syntax error { } else { forget(); } token = get(); if (token.code != TokenCode.Identifier) // Syntax error { } else { Token id = token; forget(); token = get(); if (token.code == TokenCode.Colon) { forget(); // handler.identifier = id.image; token = get(); if (token.code != TokenCode.Identifier) // Syntax error { } forget(); token = id; } UNIT_REF unit_ref = UNIT_REF.parse(null, false, context); // CHECK!! handler.unit_ref = unit_ref; unit_ref.parent = handler; } token = get(); if (token.code != TokenCode.RParen) // Syntax error { } forget(); BODY.parse(TokenCode.Catch, TokenCode.Else, TokenCode.End, handler); token = get(); // just to get the span... handler.setSpan(begin, token); Context.exit(); context.add(handler); }
/// <summary> /// The function processes all kinds of statements including /// assignments, calls, and variable/constant declarations. /// </summary> /// <param name="context"></param> /// <returns>true, if any construct (a statement, or a simple declaration) /// was processed, and false otherwise.</returns> public static bool parse(iSCOPE context, TokenCode stop1, TokenCode stop2, TokenCode stop3) { Debug.Indent(); Debug.WriteLine("Entering STATEMENT.parse"); bool result = true; Token token = get(); Token begin = token; if (token.code == stop1 && stop1 != TokenCode.ERROR) { goto Finish; } if (token.code == stop2 && stop2 != TokenCode.ERROR) { goto Finish; } if (token.code == stop3 && stop3 != TokenCode.ERROR) { goto Finish; } switch (token.code) { // case TokenCode.Pure: -- doesn't make any sense case TokenCode.Safe: case TokenCode.Routine: ROUTINE.parse(token, false, false, false, 0, context); break; case TokenCode.If: IF.parse(context); break; case TokenCode.While: case TokenCode.Loop: LOOP.parse(null, context); break; // Break // : break [ Label ] // // Label // : Identifier case TokenCode.Break: BREAK.parse(context); break; // Statement // : ... // | raise [ Expression ] case TokenCode.Raise: forget(); RAISE.parse(token.span, context); break; // Statement // : ... // | check PredicatesList end // | ... case TokenCode.Check: CHECK.parse(context); break; // Statement // : ... // | return [ Expression ] // | ... case TokenCode.Return: forget(); EXPRESSION expr = EXPRESSION.parse(null, context); // can be null RETURN ret = new RETURN(expr); if (expr != null) { expr.parent = ret; ret.setSpan(begin.span, expr.span); } else { ret.setSpan(begin); } context.add(ret); break; // Statement // : ... // | Try // | ... // // Try // : try { Statement } Catches [ Else ] end // // Catches // : catch [ "(" [ Identifier ":" ] Type ")" ] { Statement } // // Else // : else { Statement } case TokenCode.Try: TRY.parse(context); break; // Statement // : ... // | ? Identifier // | ... // case TokenCode.Question: break; case TokenCode.Init: // Initializer call forget(); Token start = token; DECLARATION init = Context.find(INITIALIZER.initName); EXPRESSION initRef; if (init != null) { initRef = new REFERENCE(init); } else { initRef = new UNRESOLVED(context, new IDENTIFIER(INITIALIZER.initName)); } CALL call = new CALL(initRef); token = expect(TokenCode.LParen); while (true) { EXPRESSION argument = EXPRESSION.parse(null, context); call.add(argument); argument.parent = call; token = get(); if (token.code == TokenCode.Comma) { forget(); continue; } break; } token = expect(TokenCode.RParen); call.setSpan(start.span, token.span); context.add(call); break; case TokenCode.Identifier: { // Several different cases: // - a label in front of while/loop // - a declaration // - a statement forget(); Token next = get(); if (next.code == TokenCode.LParen) { forget(); TokenCode codeAfter = saveTokensUntilRightParenth(next); switch (codeAfter) { case TokenCode.Colon: case TokenCode.Is: // case TokenCode.Do: case TokenCode.Arrow: //This as a routine declaration!! ROUTINE.parse(token, false, false, false, 0, context); goto Weiter; } } EXPRESSION attempt = EXPRESSION.parse(token, context); if (attempt is UNRESOLVED) { // Might be a label or a declaration... Token idd = new Token(attempt.span, TokenCode.Identifier, (attempt as UNRESOLVED).name.identifier, new Category(CategoryCode.identifier)); token = get(); switch (token.code) { case TokenCode.Is: case TokenCode.Comma: // This is definitely a declaration forget(); VARIABLE.parse(false, false, false, false, idd, token, context); goto Weiter; case TokenCode.Colon: forget(); Token token2 = get(); if (token2.code == TokenCode.While || token2.code == TokenCode.Loop) { // This is a real label! Don't 'forget()'. LOOP.parse(idd, context); } else { // This is definitely a variable declaration. // Don't forget() VARIABLE.parse(false, false, false, false, idd, token, context); } goto Weiter; default: // Nothing to do; just going further break; } } // 'attempt' is something else: a call or the left part of an assignment token = get(); if (token.code == TokenCode.Assign) { forget(); EXPRESSION right = EXPRESSION.parse(null, context); ASSIGNMENT res = new ASSIGNMENT(attempt, right); res.setSpan(attempt.span, right.span); context.add(res); } else { if (!(attempt is CALL)) // something's wrong { result = false; } context.add(attempt); } Weiter: break; } case TokenCode.Const: // Something like // const a is 5... // OR // const is a, b, ... end forget(); token = get(); if (token.code == TokenCode.Is) { forget(); CONSTANT.parse(context); } else { VARIABLE.parse(false, false, true, false, null, null, context); } break; default: // Something else, e.g., (a... or this... // Either a function call or an assignment. // // this := ... // (if cond then a else b).f ... // ^ EXPRESSION e = EXPRESSION.parse(null, context); if (e == null) { // Either an error or just the end of statement sequence result = false; break; } token = get(); if (token.code == TokenCode.Assign) { forget(); EXPRESSION right = EXPRESSION.parse(null, context); ASSIGNMENT assignment = new ASSIGNMENT(e, right); assignment.setSpan(e.span, right.span); context.add(assignment); } else { context.add(e); } break; } Finish: Debug.WriteLine("Exiting STATEMENT.parse"); Debug.Unindent(); return(result); }
/// <summary> /// /// <syntax><code> /// Объявление-переменных /// : Список-идентификаторов [ : Спецификатор-типа ] is Выражение /// | Список-идентификаторов : Спецификатор-типа /// /// Спецификатор-типа /// : [ ? | ref | val | concurrent ] Тип /// | as Составное-имя /// </code></syntax> /// </summary> /// <param name="id"></param> /// <returns></returns> public static void parse(bool hidden, bool ffinal, bool isConst, bool isOverride, Token id, Token afterId, iSCOPE context) { Debug.Indent(); Debug.WriteLine("Entering VARIABLE.parse"); TYPE type = null; EXPRESSION initializer = null; bool RefVal = false; // 'val' by default bool Conc = false; bool Abstr = false; bool Foreign = false; Token token = id; Span final = null; // If id==null, then we just start processing the declaration. // In this case, always afterId==null. // // If id != null then it contains an identifier. // In this case, afterId contains ':', ',' or 'is' - three // options starting a declaration. List <Token> identifiers = new List <Token>(); if (token == null) { // We just start parsing variable declaration token = get(); forget(); identifiers.Add(token); // Parsing the rest of identifiers in the list (if any) while (true) { token = get(); if (token.code != TokenCode.Comma) { break; } forget(); token = expect(TokenCode.Identifier); identifiers.Add(token); } } else { if (afterId.code == TokenCode.Is) { // id is ... identifiers.Add(id); token = afterId; } else if (afterId.code == TokenCode.Colon) { // 'token' contains an identifier. // Check what's after this identifier? // // id : ... // ^ identifiers.Add(id); token = afterId; } else if (afterId.code == TokenCode.Comma) { // 'token' contains an identifier, // and comma goes after it (comma was parsed already). // // id, ... // ^ identifiers.Add(id); // Parsing the rest of the list of identifiers. while (true) { token = expect(TokenCode.Identifier); identifiers.Add(token); if (token.code != TokenCode.Comma) { break; } forget(); } } else { // Syntax error error(afterId, "syntax-error", "declaration"); } } // Here, we have parsed the list of identifiers. // 'token' contains the token after the list. // Only two valid options are ':' or 'is'. if (token.code == TokenCode.Colon) { // Type is expected. if (afterId == null) { forget(); } type = parseTypeSpecifier(context, out RefVal, out Conc, out final); token = get(); } if (token.code == TokenCode.Is) { forget(); token = get(); if (token.code == TokenCode.Abstract) { forget(); Abstr = true; final = token.span; } else if (token.code == TokenCode.Foreign) { forget(); Foreign = true; final = token.span; } else { forget(); initializer = EXPRESSION.parse(token, context); if (type == null) { // Type inference // initializer.calculateType(); type = initializer.type; } final = initializer.span; } } // Here, we have the list of identifiers, their type, // and perhaps the initializer. // Create the final node(s) for variable declaration(s) // out of identifier(s), type and initializer. foreach (Token ident in identifiers) { VARIABLE varDecl = new VARIABLE(new IDENTIFIER(ident), type, initializer); varDecl.setSpecs(hidden, ffinal); varDecl.setVarSpecs(isConst, isOverride, RefVal, Conc, Abstr, Foreign); varDecl.setSpan(ident.span, final != null ? final : ident.span); context.add(varDecl); varDecl.parent = context.self; if (type != null) { type.parent = varDecl; } if (initializer != null) { initializer.parent = varDecl; } } Debug.WriteLine("Exiting VARIABLE.parse"); Debug.Unindent(); }