TypeAst FuncType(TypeAst baseType, bool mutable) { if (mutable) { throw new Exception("func code cannot be mutable"); } Token open = Match(TokenKind.LeftParen); bool vaArg = false; List <TypeAst> paramTypes = new List <TypeAst>(); while (current.kind is not TokenKind.Eof and not TokenKind.RightParen) { if (current.kind is TokenKind.DotDotDot) { vaArg = true; break; } paramTypes.Add(Type()); if (current.kind is not TokenKind.RightParen) { Match(TokenKind.Comma); } } Match(TokenKind.RightParen); return(new FuncTypeAst(baseType, open, paramTypes.ToArray(), vaArg)); }
VarAst Var(string[] metadata, Visibility visibility, bool mutable, TypeAst type, Token name, string?asmName) { scope.DefineVar(name.text); if (asmName is null) { if (current.kind is TokenKind.Colon) { Next(); asmName = Match(TokenKind.Str).text; } else { asmName = $"Syv${name.text}"; } } ExprAst initializer = new ExprAst(Token.devault); if (current.kind is TokenKind.Eql) { Next(); initializer = Expr(); } EndLine(); return(new VarAst(metadata, visibility, mutable, type, name, asmName, initializer)); }
TypeAst TypeExt(TypeAst baseType) { bool mutable = false; if (current.kind is TokenKind.MutableKeyword) { mutable = true; Next(); } switch (current.kind) { case TokenKind.Star: return(TypeExt(PtrType(baseType, mutable))); case TokenKind.LeftBracket: return(TypeExt(ArrayType(baseType, mutable))); case TokenKind.LeftParen: return(TypeExt(FuncType(baseType, mutable))); default: return(baseType); } }
ExprAst PostExpr(ExprAst operand) { Loop: if (postOps.Contains(current.kind)) { Token token = Next(); Enum op = PostOpcode(token.kind); operand = new PostExprAst(token, op, operand); goto Loop; } if (current.kind is TokenKind.LeftParen) { Token open = Next(); List <ExprAst> args = new List <ExprAst>(); while (current.kind is not TokenKind.Eof and not TokenKind.RightParen) { args.Add(Expr()); if (current.kind is not TokenKind.RightParen) { Match(TokenKind.Comma); } } Match(TokenKind.RightParen); operand = new CallExprAst(operand, open, args.ToArray()); goto Loop; } if (current.kind is TokenKind.Dot) { Next(); Token name = Match(TokenKind.Identifier); operand = new MemberExprAst(operand, name); goto Loop; } if (current.kind is TokenKind.AsKeyword) { Token keywrd = Next(); TypeAst to = Type(); operand = new BitCastExprAst(operand, keywrd, to); goto Loop; } if (current.kind is TokenKind.ToKeyword) { Token keywrd = Next(); TypeAst to = Type(); operand = new CastExprAst(operand, keywrd, to); goto Loop; } if (current.kind is TokenKind.LeftBracket) { Token open = Next(); ExprAst idx = Expr(); Match(TokenKind.RightBracket); operand = new IndexExprAst(operand, open, idx); goto Loop; } return(operand); }
TypeAst ArrayType(TypeAst baseType, bool mutable) { Token open = Match(TokenKind.LeftBracket); ExprAst length = Expr(); Match(TokenKind.RightBracket); return(new ArrayTypeAst(baseType, mutable, open, length)); }
DeclFuncAst DeclFunc(string[] metadata, Visibility visibility, bool mutable, TypeAst retType, Token name) { scope.DefineFunc(name.text); List <ParamAst> paramz = new List <ParamAst>(); Match(TokenKind.LeftParen); bool vaArg = false; while (current.kind is not TokenKind.Eof and not TokenKind.RightParen) { if (current.kind is TokenKind.DotDotDot) { Next(); vaArg = true; break; } ParamAst param = Param(); paramz.Add(param); if (current.kind is not TokenKind.RightParen) { Match(TokenKind.Comma); } } Match(TokenKind.RightParen); string asmName; if (current.kind is TokenKind.Colon) { Next(); asmName = Match(TokenKind.Str).text; } else if (metadata.Contains("naked")) { asmName = name.text; } else { StringBuilder sb = new StringBuilder("Syf$"); sb.Append(name.text); foreach (ParamAst param in paramz) { sb.Append(';'); sb.Append(param.type.name); } asmName = sb.ToString(); } MaybeEndLine(); // TODO: class fn decls return(new DeclFuncAst(metadata, visibility, mutable, retType, name, asmName, paramz.ToArray(), vaArg)); }
SizeofExprAst SizeofExpr() { Token name = Match(TokenKind.Identifier); Match(TokenKind.LeftParen); TypeAst type = Type(); Match(TokenKind.RightParen); return(new SizeofExprAst(name, type)); }
DeclVarAst DeclVar(string[] metadata, Visibility visibility, bool mutable, TypeAst type, Token name) { scope.DefineVar(name.text); string asmName = $"Syv${name.text}"; if (current.kind is TokenKind.Colon) { Next(); name = Match(TokenKind.Str); } return(new DeclVarAst(metadata, visibility, mutable, type, name, asmName)); }
UsingAst Using(Visibility visibility) { Token keywrd = Match(TokenKind.UsingKeyword); TypeAst realType = Type(); Match(TokenKind.AsKeyword); string alias = Name(); EndLine(); return(new UsingAst(visibility, keywrd, realType, alias)); }
FuncAst Func(string className, FieldAst[] fields) { string[] metadata = MetaData(); Visibility visibility; switch (current.kind) { case TokenKind.PublicKeyword: Next(); visibility = LLVMDefaultVisibility; break; case TokenKind.PrivateKeyword: Next(); visibility = LLVMHiddenVisibility; break; case TokenKind.ProtectedKeyword: Next(); visibility = LLVMProtectedVisibility; break; default: visibility = LLVMDefaultVisibility; break; } ; bool mutable; if (mutable = current.kind is TokenKind.MutableKeyword) { Next(); } TypeAst retType = Type(); Token name = Match(TokenKind.Identifier); string asmName = $"{className}.{name.text}"; EnterScope(); scope.DefineVar("this"); foreach (FieldAst field in fields) { scope.DefineVar(field.name); } FuncAst func = Func(metadata, visibility, mutable, retType, name, asmName, false); ExitScope(); return(func); }
GroupExprAst GroupExpr(TypeAst groupType) { Token open = Match(TokenKind.LeftBrace); List <ExprAst> members = new List <ExprAst>(); while (current.kind is not TokenKind.Eof and not TokenKind.RightBrace) { members.Add(Expr()); if (current.kind is not TokenKind.RightBrace) { Match(TokenKind.Comma); } } Match(TokenKind.RightBrace); return(new GroupExprAst(groupType, open, members.ToArray())); }
ParamAst Param() { string[] metadata = MetaData(); bool mutable; if (mutable = current.kind is TokenKind.MutableKeyword) { Next(); } TypeAst type = Type(); Token token; string name; if (current.kind is TokenKind.Identifier) { token = Next(); name = token.text; } else { token = type.token; name = string.Empty; } ExprAst defaultExpr = new ExprAst(Token.devault); if (current.kind is TokenKind.Eql) { Next(); defaultExpr = Expr(); } return(new ParamAst(metadata, mutable, type, token, name, defaultExpr)); }
StmtAst Stmt() { switch (current.kind) { case TokenKind.LeftBrace: return(Block()); case TokenKind.IfKeyword: return(If()); case TokenKind.WhileKeyword: return(While()); case TokenKind.ForKeyword: return(For()); case TokenKind.BreakKeyword: return(Break()); case TokenKind.BreakAllKeyword: return(BreakAll()); case TokenKind.RetKeyword: return(Ret()); } string[] metadata = MetaData(); bool illegal = true; Visibility visibility; switch (current.kind) { case TokenKind.PublicKeyword: Next(); visibility = LLVMDefaultVisibility; break; case TokenKind.PrivateKeyword: Next(); visibility = LLVMHiddenVisibility; break; case TokenKind.ProtectedKeyword: Next(); visibility = LLVMProtectedVisibility; break; default: visibility = LLVMDefaultVisibility; illegal = false; break; } ; bool mutable; if (mutable = current.kind is TokenKind.MutableKeyword) { Next(); } if (current.kind is TokenKind.EnumKeyword) { return(Enum(metadata, visibility)); } if (current.kind is TokenKind.StructKeyword) { return(Struct(metadata, visibility)); } if (current.kind is TokenKind.ClassKeyword) { return(Class(metadata, visibility)); } if (current.kind is TokenKind.UsingKeyword) { return(Using(visibility)); } if (current.kind is TokenKind.LinkKeyword) { return(Link(visibility)); } if (current.kind is TokenKind.DeclKeyword) { Next(); TypeAst type = Type(); Token name = Match(TokenKind.Identifier); if (current.kind is TokenKind.LeftParen) { return(DeclFunc(metadata, visibility, mutable, retType: type, name)); } return(DeclVar(metadata, visibility, mutable, type, name)); } if (current.kind is TokenKind.Identifier && !(scope.VarExists(current.text) || scope.FuncExists(current.text)) && IsType(current)) { TypeAst type = Type(); Token name = Match(TokenKind.Identifier); string? asmName = null; if (current.kind is TokenKind.Colon) { Next(); asmName = Match(TokenKind.Str).text; } if (current.kind is TokenKind.LeftParen or TokenKind.LeftBrace or TokenKind.Arrow) { return(Func(metadata, visibility, mutable, retType: type, name, asmName)); } return(Var(metadata, visibility, mutable, type, name, asmName)); } if (!illegal) { return(ExprStmt()); } throw new Exception("Illegal"); }
FuncAst Func(string[] metadata, Visibility visibility, bool mutable, TypeAst retType, Token name, string?asmName, bool asmNameIsName = true) { EnterScope(); bool vaArg = false; List <ParamAst> paramz = new List <ParamAst>(); Match(TokenKind.LeftParen); while (current.kind is not TokenKind.Eof and not TokenKind.RightParen) { if (current.kind is TokenKind.DotDotDot) { Next(); vaArg = true; break; } ParamAst param = Param(); paramz.Add(param); scope.DefineVar(param.name); if (current.kind is not TokenKind.RightParen) { Match(TokenKind.Comma); } } Match(TokenKind.RightParen); if (asmName is null || !asmNameIsName) { if (current.kind is TokenKind.Colon) { Next(); asmName = Match(TokenKind.Str).text; } else if (metadata.Contains("naked")) { asmName = name.text; } else { StringBuilder sb = new StringBuilder(mutable ? "Symf$" : "Syf$"); sb.Append(asmNameIsName ? name.text : asmName); foreach (ParamAst param in paramz) { sb.Append(';'); sb.Append(param.type.name); } asmName = sb.ToString(); } } // Single Expr Func if (current.kind is TokenKind.Arrow) { Next(); ExprAst expr = Expr(); MaybeEndLine(); return(new FuncAst(metadata, visibility, mutable, retType, name, asmName ?? name.text, paramz.ToArray(), vaArg, new StmtAst[] { new RetStmtAst(Token.devault, expr) })); } List <StmtAst> body = new List <StmtAst>(); Match(TokenKind.LeftBrace); while (current.kind is not TokenKind.Eof and not TokenKind.RightBrace) { body.Add(Stmt()); } ExitScope(); Match(TokenKind.RightBrace); MaybeEndLine(); scope.DefineFunc(name.text); return(new FuncAst(metadata, visibility, mutable, retType, name, asmName ?? name.text, paramz.ToArray(), vaArg, body.ToArray())); }
TypeAst PtrType(TypeAst baseType, bool mutable) { Token token = Match(TokenKind.Star); return(new PtrTypeAst(baseType, mutable, token)); }
ExprAst PrimExpr() { switch (current.kind) { case TokenKind.Percent: Token op = Next(); return(new PreExprAst(PreOpcode(op.kind), op, PrimExpr())); case TokenKind.Identifier: { if (scope.VarExists(current.text)) { return(new VarExprAst(Next())); } if (current.text is "stalloc") { return(StallocExpr()); } if (current.text is "sizeof") { return(SizeofExpr()); } if (scope.FuncExists(current.text)) // fnptr overloads { return(new FuncPtrAst(Next())); } if (!IsType(current)) { BadCode.Report(new SyntaxError($"symbol '{current.text}' doesn't exist", current)); } TypeAst type = Type(); if (current.kind is TokenKind.LeftBracket) { return(ArrayExpr(eleType: type)); } return(GroupExpr(groupType: type)); } case TokenKind.LeftParen: Next(); if (IsType(current)) { TypeAst to = Type(); Token open = Match(TokenKind.RightParen); ExprAst value = PreExpr(); return(new CastExprAst(value, open, to)); } ExprAst expr = Expr(); Match(TokenKind.RightParen); return(expr); case TokenKind.LeftBracket: if (IsType(next)) { Next(); TypeAst to = Type(); Token open = Match(TokenKind.RightBracket); ExprAst value = PreExpr(); return(new BitCastExprAst(value, open, to)); } return(ArrayExpr()); default: return(LiteralExpr()); } }