/// <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(); }
/// <summary> /// /// </summary> /// <syntax> /// UnitTypeName : CompoundName [ GenericInstantiation ] /// /// GenericInstantiation : "[" (Type|Expression) { "," (Type|Expression) } "]" /// </syntax> /// <returns></returns> public static UNIT_REF parse(Token id, bool opt, iSCOPE context) { Debug.Indent(); Debug.WriteLine("Entering UNIT_REF.parse"); Token token = null; // We assume that 'id' is 'identifier'. if (id == null) { token = get(); forget(); } else { token = id; } token = IDENTIFIER.parseCompoundName(token); if (token == null) /* an error was detected earlier */ return { (null); } Token start = token; UNIT_REF unit_ref = new UNIT_REF(token.image); unit_ref.opt = opt; unit_ref.as_sign = true; DECLARATION unit = Context.find(token); if (unit != null && (unit is UNIT || unit is FORMAL_TYPE)) { unit_ref.unit_ref = unit; } token = get(); if (token.code == TokenCode.LBracket) { forget(); while (true) { TYPE type = null; token = get(); if (token.code == TokenCode.LParen) { type = TUPLE_TYPE.parse(context); unit_ref.add(type); goto Delimiter; } EXPRESSION expr = EXPRESSION.parse(null, context); if (expr is REFERENCE || expr is UNRESOLVED) { string name = null; if (expr is REFERENCE) { if ((expr as REFERENCE).declaration is UNIT) { name = (expr as REFERENCE).declaration.name.identifier; } else { goto NonType; } } else // UNRESOLVED { name = (expr as UNRESOLVED).name.identifier; } id = new Token(expr.span, TokenCode.Identifier, name, new Category(CategoryCode.identifier)); type = UNIT_REF.parse(id, false, context); // Recursive call unit_ref.add(type); type.parent = unit_ref; goto Delimiter; } // else -- expr is perhaps a non-type argument NonType: token = get(); if (token.code == TokenCode.DotDot) { // This is actually a range _type_ forget(); EXPRESSION right = EXPRESSION.parse(null, context); RANGE_TYPE range = new RANGE_TYPE(expr, right); range.setSpan(expr.span, right.span); unit_ref.add(range); range.parent = unit_ref; } else // Definitely a non-type argument { unit_ref.add(expr); expr.parent = unit_ref; } Delimiter: token = get(); switch (token.code) { case TokenCode.Comma: forget(); continue; case TokenCode.RBracket: forget(); goto Finish; default: { /* Syntax error in generic actuals */ break; } } } Finish: unit_ref.setSpan(start.span, token.span); } else { unit_ref.setSpan(start); } Debug.WriteLine("Exiting UNIT_REF.parse"); Debug.Unindent(); return(unit_ref); }
public VARIABLE(IDENTIFIER n = null, TYPE t = null, EXPRESSION i = null) : base(n) { type = t; initializer = i; }