private static AstStruct ParseStruct(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.Struct); var ident = tks.Expect(TokenType.Ident).StringValue; List <AstType> genericTypeList = null; if (tks.Accept(TokenType.LessThan) != null) { genericTypeList = ParseTypeList(tks, false, true); tks.Expect(TokenType.GreaterThan); } tks.Expect(TokenType.LCurBracket); var members = new List <AstDeclaration>(); while (tks.Accept(TokenType.RCurBracket) == null) { var memberId = tks.Expect(TokenType.Ident).StringValue; tks.Expect(TokenType.Colon); var membType = ParseType(tks, true, true); tks.Expect(TokenType.Semicolon); members.Add(new AstDeclaration(si, memberId, membType, null)); } return(new AstStruct(si, ident, members, genericTypeList)); }
// <foreign> ::= 'foreign' 'func' <string> '(' <func-param-list> ')' ';' // | 'foreign' 'func' <string> '(' <func-param-list> ')' -> <ident> ';' private static AstForeign ParseForeign(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.Foreign); tks.Expect(TokenType.Func); var name = tks.Expect(TokenType.Ident).StringValue; var cname = name; if (tks.Accept(TokenType.As) != null) { cname = tks.Accept(TokenType.String).WithoutQuotes(); } tks.Expect(TokenType.LParen); var paramList = ParseFuncParamList(tks); bool isVarArgs = tks.Accept(TokenType.DotDotDot) != null; tks.Expect(TokenType.RParen); var retType = tks.Accept(TokenType.RightArrow) != null ? ParseType(tks, false, false) : new AstType(si, "void", 0, 0, false, false); tks.Expect(TokenType.Semicolon); return(new AstForeign(si, paramList, name, cname, retType, isVarArgs)); }
private static bool ParseExtendParamList(TokenStream tks, string typeToExtend, List <AstDeclaration> @params) { var si = tks.SourceInfo; var firstParam = tks.Accept(TokenType.Ident); bool usesThisPtr = false; if (firstParam != null) { // no colon -> no type decl -> using thisptr AstType firstParType; if (tks.Accept(TokenType.Colon) == null) { usesThisPtr = true; if (tks.Peek().Type != TokenType.RParen) { tks.Expect(TokenType.Comma); } firstParType = new AstType(si, typeToExtend, 1, 0, false, false); } else { firstParType = ParseType(tks, false, true); if (tks.Peek().Type != TokenType.RParen) { tks.Expect(TokenType.Comma); } } @params.Add(new AstDeclaration(si, firstParam.StringValue, firstParType, null)); var otherParams = ParseFuncParamList(tks); @params.AddRange(otherParams); } return(usesThisPtr); }
// <primary> ::= '(' <expr> ')' // | <number> // | <ident> // | <string> private static AstExpression ParsePrimary(TokenStream tks) { var si = tks.SourceInfo; var save = tks.Index; var tk = tks.Accept(TokenType.LParen); if (tk != null) { var expr = ParseAssign(tks); tks.Expect(TokenType.RParen); return(expr); } tk = tks.Accept(TokenType.Ident, TokenType.Number, TokenType.String); if (tk != null) { switch (tk.Type) { case TokenType.Ident: return(new AstIdent(si, tk.StringValue)); case TokenType.Number: return(new AstNumber(si, tk.ToDecimal())); case TokenType.String: return(new AstString(si, tk.StringValue)); } } tks.Restore(save); return(null); }
// <decl-assign> ::= <ident> ':' <ident> '=' <assign> // | <ident> ':' '=' <assign> // | <ident> ':' <ident> // | <ident> ':' <ident> [ <integer> ] private static AstDeclaration ParseVariableDeclaration(TokenStream tks) { var si = tks.SourceInfo; var save = tks.Index; var ident = tks.Accept(TokenType.Ident); if (ident == null) { tks.Restore(save); return(null); } if (tks.Accept(TokenType.Colon) == null) { tks.Restore(save); return(null); } AstType varType = null; if (tks.Peek().Type != TokenType.Assign) { varType = ParseType(tks, true, false); } AstExpression rhs = null; if (tks.Accept(TokenType.Assign) != null) { rhs = ParseAssign(tks); if (rhs == null) { throw new Exception("Expected expression on rhs of variable declaration"); } } return(new AstDeclaration(si, ident.StringValue, varType, rhs)); }
private static AstExpression ParseNewExpr(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.New); var what = tks.Expect(TokenType.Ident).StringValue; if (tks.Accept(TokenType.LParen) != null) { var ctorCall = new AstCall(si, new AstIdent(si, what), ParseExpressionList(tks)); tks.Expect(TokenType.RParen); return(new AstUnaryOp(si, TokenType.New, ctorCall)); } var ptrDepth = 1; while (tks.Accept(TokenType.Star) != null) { ptrDepth++; } tks.Expect(TokenType.LSquBracket); var size = ParseExpression(tks); tks.Expect(TokenType.RSquBracket); return(new AstNewArrayOp(si, size, what, ptrDepth)); }
// <if-stmt> ::= 'if' <assign> '{' <body> '}' // ::= 'if' <assign> '{' <body> '}' 'else' '{' <body> '}' // ::= 'if' <assign> '{' <body> '}' 'else' <if-stmt> private static AstIf ParseIf(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.If); var cond = ParseAssign(tks); tks.Expect(TokenType.LCurBracket); var trueBody = ParseBody(tks); tks.Expect(TokenType.RCurBracket); var falseBody = new List <AstNode>(); if (tks.Accept(TokenType.Else) != null) { if (tks.Accept(TokenType.LCurBracket) != null) { falseBody = ParseBody(tks); tks.Expect(TokenType.RCurBracket); } else { tks.Expect(TokenType.If); tks.Rewind(); falseBody.Add(ParseIf(tks)); } } return(new AstIf(si, cond, trueBody, falseBody)); }
private bool ReturnStatement() { if (!TokenStream.Accept(TokenType.Word, "return")) { return(false); } if (IsReference(TokenStream.Peek()) || TokenStream.Pass(TokenType.Number) || TokenStream.Pass(TokenType.String) || (TokenStream.Pass(TokenType.Delimiter) && !TokenStream.Accept(TokenType.Delimiter, ";"))) { if (currentMethod.Name == IdentConstructor) { throw new CompilerException("Constructors must return a 'this' pointer."); } Ternary(); } else if (currentMethod.Name == IdentConstructor) { Instructions.Add(new Instruction(Opcode.GetThis)); } Instructions.Add(new Instruction(Opcode.Return)); TokenStream.Accept(TokenType.Delimiter, ";"); return(true); }
private static AstFor ParseForIn(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.For); var ident = tks.Expect(TokenType.Ident).StringValue; tks.Expect(TokenType.In); var @from = ParseExpression(tks); tks.Expect(TokenType.DotDot); var to = ParseExpression(tks); var opTk = tks.Accept(TokenType.Plus, TokenType.Minus); var updateOp = opTk?.Type ?? TokenType.Plus; tks.Expect(TokenType.LCurBracket); var body = ParseBody(tks); tks.Expect(TokenType.RCurBracket); var pre = new AstDeclaration(si, ident, null, @from); var condOp = (updateOp == TokenType.Plus) ? TokenType.LessThanEquals : TokenType.GreaterThanEquals; var itrId = new AstIdent(si, ident); var cond = new AstBinaryOp(si, itrId, condOp, to); var update_ = new AstBinaryOp(si, itrId, updateOp, new AstNumber(si, 1)); var update = new AstAssign(si, itrId, update_); return(new AstFor(si, new List <AstNode> { pre }, cond, new List <AstExpression> { update }, body)); }
private void PrimaryReference() { int refIndex = TokenStream.Position; GetReference(); if (TokenStream.Accept(TokenType.Delimiter, "++")) { TokenStream.Position = refIndex; GetReference(); Instructions.Add(new Instruction(Opcode.Push, 1)); Instructions.Add(new Instruction(Opcode.Add)); TokenStream.Position = refIndex; SetReference(); TokenStream.Read(); } else if (TokenStream.Accept(TokenType.Delimiter, "--")) { TokenStream.Position = refIndex; GetReference(); Instructions.Add(new Instruction(Opcode.Push, 1)); Instructions.Add(new Instruction(Opcode.Subtract)); TokenStream.Position = refIndex; SetReference(); TokenStream.Read(); } }
private void PrefixIncrement() { if (TokenStream.Accept(TokenType.Delimiter, "++")) { TokenStream.PushPosition(); GetReference(); Instructions.Add(new Instruction(Opcode.Push, 1)); Instructions.Add(new Instruction(Opcode.Add)); TokenStream.PopPosition(); TokenStream.PushPosition(); SetReference(); TokenStream.PopPosition(); GetReference(); } else if (TokenStream.Accept(TokenType.Delimiter, "--")) { TokenStream.PushPosition(); GetReference(); Instructions.Add(new Instruction(Opcode.Push, 1)); Instructions.Add(new Instruction(Opcode.Subtract)); TokenStream.PopPosition(); TokenStream.PushPosition(); SetReference(); TokenStream.PopPosition(); GetReference(); } }
private void Unary() { if (Parser.IsAddOperation(TokenStream.Peek())) { UnarySign(); } else if (TokenStream.Accept(TokenType.Delimiter, "!")) { Primary(); Instructions.Add(new Instruction(Opcode.BitwiseNot)); } else if (TokenStream.Accept(TokenType.Delimiter, "~")) { Primary(); Instructions.Add(new Instruction(Opcode.BitwiseNegate)); } else if (Parser.IsCastOperation(TokenStream.Peek())) { TypeCast(); } else if (Parser.IsIncrementOperation(TokenStream.Peek())) { PrefixIncrement(); } else { Primary(); } }
private void Multiplicative() { Unary(); while (Parser.IsMulOperation(TokenStream.Peek())) { if (TokenStream.Accept(TokenType.Delimiter, "*")) { Unary(); Instructions.Add(new Instruction(Opcode.Multiply)); } else if (TokenStream.Accept(TokenType.Delimiter, "/")) { Unary(); Instructions.Add(new Instruction(Opcode.Divide)); } else if (TokenStream.Accept(TokenType.Delimiter, "%")) { if (TokenStream.Pass(TokenType.Delimiter, "[")) { // Write hacks err day Ternary(); Instructions.Add(new Instruction(Opcode.ClassCallStatic, "__str Format", 2)); } else { Unary(); Instructions.Add(new Instruction(Opcode.Modulo)); } } } }
private void Ternary() { LogicalOr(); while (TokenStream.Accept(TokenType.Delimiter, "?")) { Label labelElse = new Label(this); Label labelEnd = new Label(this); Instructions.Add(new Instruction(Opcode.Push, 0)); Instructions.Add(new Instruction(Opcode.CompareNotEqual)); Instructions.Add(new Instruction(Opcode.IfFalse, 0)); labelElse.PatchHere(); LogicalOr(); Instructions.Add(new Instruction(Opcode.Jump, 0)); labelEnd.PatchHere(); TokenStream.Expect(TokenType.Delimiter, ":"); labelElse.Mark(); LogicalOr(); labelEnd.Mark(); labelElse.Fix(); labelEnd.Fix(); } }
private bool BreakStatement() { if (!TokenStream.Accept(TokenType.Word, "break")) { return(false); } if (breakStack.Count == 0) { throw new CompilerException("Nothing to break from."); } if (TokenStream.Pass(TokenType.Number)) { long count = TokenStream.ReadVariant().IntValue; if (breakStack.Count < count) { throw new CompilerException("Cannot break from {0} scopes deep, because we are not {0} scopes deep at this time.", count); } Instructions.Add(new Instruction(Opcode.Jump, 0)); Label[] labelArray = breakStack.ToArray(); labelArray[count - 1].PatchHere(); } else { Instructions.Add(new Instruction(Opcode.Jump, 0)); breakStack.Peek().PatchHere(); } TokenStream.Accept(TokenType.Delimiter, ";"); return(true); }
// <unary-exp> ::= <postfix-exp> // | <unary-op> <unary-exp> private static AstExpression ParseUnaryOp(TokenStream tks) { var si = tks.SourceInfo; var save = tks.Index; var postfix = ParsePostfix(tks); if (postfix != null) { return(postfix); } tks.Restore(save); var op = tks.Accept(UnaryOps); if (op == null) { tks.Restore(save); return(null); } if (op.Type == TokenType.New) { tks.Restore(save); return(ParseNewExpr(tks)); } var unary = ParseUnaryOp(tks); return(new AstUnaryOp(si, op.Type, unary)); }
private bool ForStatement() { if (!TokenStream.Accept(TokenType.Word, "for")) { return(false); } Label labelStart = new Label(this); Label labelEnd = new Label(this); Label labelContinue = new Label(this); continueStack.Push(labelContinue); breakStack.Push(labelEnd); TokenStream.Expect(TokenType.Delimiter, "("); if (!Variable()) { Assignment(); } TokenStream.Accept(TokenType.Delimiter, ";"); labelStart.Mark(); Assignment(); Instructions.Add(new Instruction(Opcode.Push, 1)); Instructions.Add(new Instruction(Opcode.CompareNotEqual)); Instructions.Add(new Instruction(Opcode.IfTrue, 0)); labelEnd.PatchHere(); TokenStream.Accept(TokenType.Delimiter, ";"); TokenStream.PushPosition(); while (!TokenStream.Accept(TokenType.Delimiter, ")")) { TokenStream.Read(); } Block(); int endOfBlock = TokenStream.Position; TokenStream.PopPosition(); labelContinue.Mark(); Assignment(); TokenStream.Position = endOfBlock; Instructions.Add(new Instruction(Opcode.Jump, 0)); labelStart.PatchHere(); labelEnd.Mark(); labelContinue.Fix(); labelStart.Fix(); labelEnd.Fix(); continueStack.Pop(); breakStack.Pop(); return(true); }
private void BitwiseXor() { BitwiseAnd(); while (TokenStream.Accept(TokenType.Delimiter, "^")) { BitwiseAnd(); Instructions.Add(new Instruction(Opcode.BitwiseXor)); } }
private void BitwiseAnd() { Equality(); while (TokenStream.Accept(TokenType.Delimiter, "&")) { Equality(); Instructions.Add(new Instruction(Opcode.BitwiseAnd)); } }
private void BlockStatement() { if (!IfStatement() && !WhileStatement() && !DoWhileStatement() && !ForeachStatement() && !ForStatement() && !SwitchStatement() && !RepeatStatement() && !ReturnStatement() && !BreakStatement() && !ContinueStatement() && !Variable()) { Assignment(); TokenStream.Accept(TokenType.Delimiter, ";"); } }
private void LogicalOr() { LogicalAnd(); while (TokenStream.Accept(TokenType.Delimiter, "||")) { LogicalAnd(); Instructions.Add(new Instruction(Opcode.Add)); Instructions.Add(new Instruction(Opcode.Push, 0)); Instructions.Add(new Instruction(Opcode.CompareGreaterThan)); } }
private void LogicalAnd() { BitwiseOr(); while (TokenStream.Accept(TokenType.Delimiter, "&&")) { BitwiseOr(); Instructions.Add(new Instruction(Opcode.Add)); Instructions.Add(new Instruction(Opcode.Push, 2)); Instructions.Add(new Instruction(Opcode.CompareEqual)); } }
// <type> ::= '#' ? <ident> '*'* '[' <integer> ']' // ::= 'ref' '#'? <ident> '*'* '[' <integer> ']' private static AstType ParseType(TokenStream tks, bool allowFixedArray, bool allowGeneric) { var si = tks.Peek().SourceInfo; bool isAReference = tks.Accept(TokenType.Ref) != null; bool isGeneric = tks.Accept(TokenType.Hash) != null; var ident = tks.Expect(TokenType.Ident).StringValue; var ptrDepth = 0; while (tks.Accept(TokenType.Star) != null) { ++ptrDepth; } int fixedSize = 0; if (tks.Accept(TokenType.LSquBracket) != null) { var size = tks.Expect(TokenType.Number); if (!size.IsIntegral()) { throw new UnexpectedTokenException( TokenType.Number, string.Format( "Error: {0} : Expected integral number, got `{1}'", size.SourceInfo, size.StringValue)); } ++ptrDepth; fixedSize = (int)size.ToDecimal(); tks.Expect(TokenType.RSquBracket); } if (!allowFixedArray && fixedSize != 0) { throw new NotImplementedException(string.Format("{0} : Fixed array not allowed here.", si)); } if (!allowGeneric && isGeneric) { throw new NotImplementedException(string.Format("{0} : Generic type not allowed here.", si)); } return(new AstType(si, ident, ptrDepth, fixedSize, isAReference, isGeneric)); }
private static AstExtend ParseExtend(TokenStream tks) { var save = tks.Index; var si = tks.SourceInfo; tks.Expect(TokenType.Extend); if (tks.Accept(TokenType.ArithNot) != null) { // destructor tks.Restore(save); return(ParseDestructor(tks)); } var typeToExtend = tks.Expect(TokenType.Ident).StringValue; if (tks.Accept(TokenType.LParen) != null) { // constructor tks.Restore(save); return(ParseConstructor(tks)); } var name = tks.Expect(TokenType.Ident).StringValue; tks.Expect(TokenType.LParen); var @params = new List <AstDeclaration>(); var usesThisPtr = ParseExtendParamList(tks, typeToExtend, @params); tks.Expect(TokenType.RParen); var retType = tks.Accept(TokenType.RightArrow) != null ? ParseType(tks, false, true) : new AstType(si, "void", 0, 0, false, false); tks.Expect(TokenType.LCurBracket); var body = ParseBody(tks); tks.Expect(TokenType.RCurBracket); return(new AstExtend(si, typeToExtend, name, usesThisPtr, @params, retType, body)); }
private static List <AstType> ParseTypeList(TokenStream tks, bool allowFixedArray, bool allowGenerics) { var list = new List <AstType>(); while (true) { var type = ParseType(tks, allowFixedArray, allowGenerics); list.Add(type); if (tks.Accept(TokenType.Comma) == null) { return(list); } } }
private static List <AstDeclaration> ParseFuncParamList(TokenStream tks) { var si = tks.SourceInfo; var parameters = new List <AstDeclaration>(); while (true) { var ident = tks.Accept(TokenType.Ident); if (ident != null) { tks.Expect(TokenType.Colon); var parType = ParseType(tks, false, true); parameters.Add(new AstDeclaration(si, ident.StringValue, parType, null)); if (tks.Accept(TokenType.Comma) != null) { continue; } } break; } return(parameters); }
private bool Variable() { if (TokenStream.Peek().Value != "var") { return(false); } TokenStream.Expect("var"); do { int identOffset = TokenStream.Position; string ident = TokenStream.ReadWord(); if (IsVariableInScope(ident) || IsField(ident) || IsMethod(ident) || IsConstant(ident) || IsEnumeration(ident)) { throw new CompilerException("Redeclaration of variable '{0}' in method '{1}'.", ident, currentMethod.Name); } if (Parser.IsReservedIdent(ident)) { throw new CompilerException("'{0}' is a reserved symbol.", ident); } Variant value = ParseAnnotatedVariable(); // This should be safe, if we don't have the variable in scope but it's already been created in a previous scope // then we don't want to readd it, just reference it (it will already be allocated on the stack). if (!IsVariable(ident)) { currentMethod.Variables.Add(ident, value); } scopeStack.Peek().Add(ident); if (TokenStream.Accept(TokenType.Delimiter, "=")) { TokenStream.Position = identOffset; Assignment(); } else { Instructions.Add(new Instruction(Opcode.Push, value)); Instructions.Add(new Instruction(Opcode.SetVariable, ident)); } }while (TokenStream.Accept(TokenType.Delimiter, ",")); TokenStream.Accept(TokenType.Delimiter, ";"); return(true); }
// <require> ::= 'require' <package-ident> ';' // | 'require' <package-ident> '.' '*' ';' private static AstRequire ParseRequire(TokenStream tks) { var si = tks.SourceInfo; tks.Expect(TokenType.Require); var idents = ParsePackageIdent(tks); bool usesStar = false; if (tks.Accept(TokenType.Dot) != null) { tks.Expect(TokenType.Star); usesStar = true; } tks.Expect(TokenType.Semicolon); return(new AstRequire(si, idents, usesStar)); }
private Variant ParseAnnotatedVariable() { if (!TokenStream.Accept(TokenType.Delimiter, ":")) { return(new Variant()); } string type = TokenStream.ReadWord(); switch (type) { case "nil": return(new Variant()); case "int": return(new Variant(0)); case "double": return(new Variant(0.0)); case "str": return(new Variant("") { ObjectName = "__str" }); case "list": return(new Variant(new List <Variant>()) { ObjectName = "__list" }); case "object": return(new Variant((object)null)); default: if (!IsClass(type)) { throw new CompilerException("'{0}' is not a valid variant type.", type); } return(new Variant((object)null) { ObjectName = type }); } }
private void NewObject(Class parent) { // Call constructor if there is one if (IsMethod(IdentConstructor, parent)) { // Parse arguments int argumentsPassed = ArgumentList(); Method method = GetMethod(IdentConstructor, argumentsPassed, parent); if (GetMethod(IdentConstructor, parent) == null) { throw new CompilerException("Class '{0}' has no constructor.", parent.Name); } if (method == null) { throw new CompilerException("No overload of class '{0}''s constructor accepts {1} arguments.", parent.Name, argumentsPassed); } // Create new object and call constructor Instructions.Add(new Instruction(Opcode.New, parent.Name)); Instructions.Add(new Instruction(Opcode.ClassCall, IdentConstructor, argumentsPassed)); } else { // Create new object Instructions.Add(new Instruction(Opcode.New, parent.Name)); // No constructor, read useless argument list TokenStream.Expect(TokenType.Delimiter, "("); TokenStream.Expect(TokenType.Delimiter, ")"); } // Push this object type onto the type stack so the reference can be evaluated later typeStack.Push(parent.Name); // Parse out inline method calls if (TokenStream.Accept(TokenType.Delimiter, ".")) { string tmpVarIdent = CreateTemporaryVariable(); Instructions.Add(new Instruction(Opcode.SetVariable, tmpVarIdent)); MethodCall(parent, new Instruction(Opcode.GetVariable, tmpVarIdent)); } }