private FunctionSymbol BindFunctionDeclaration(FunctionDeclarationNode node) { var seenParameterNames = new HashSet <string>(); var parameters = new List <ParameterSymbol>(); foreach (var parameterNode in node.ParametersDeclaration.Parameters) { var parameterName = parameterNode.MainToken.Text; var parameterType = BindTypeClause(parameterNode.Type); if (seenParameterNames.Add(parameterName)) { var parameter = new ParameterSymbol(parameterName, parameterType); parameters.Add(parameter); } else { diagnostics.ReportParameterAlreadyDeclared(parameterNode.MainToken, parameterName); } } var type = BindTypeClause(node.ReturnType) ?? BuiltinTypes.Void; var function = new FunctionSymbol(node.FunctionName.Text, parameters, type, node); if (Scope.TryDeclareFunction(function)) { return(function); } diagnostics.ReportSymbolAlreadyDeclared(node.FunctionName, function.Name, "Function"); return(null); }
public static void Walk([NotNull] FunctionDeclarationNode functionDeclaration, [NotNull] IList <string> list) { if (functionDeclaration.Id != null) { list.Add(functionDeclaration.Id.Name); } }
public override IEnumerable <(SyntaxNode, SyntaxDiagnostic)> Run(NamedDeclarationNode node) { if (node.VisibilityKeywordToken?.Kind != SyntaxTokenKind.PubKeyword) { yield break; } var type = node switch { ConstantDeclarationNode _ => "constant", FunctionDeclarationNode _ => "function", ExternalDeclarationNode _ => "function", _ => throw DebugAssert.Unreachable(), }; var ident = node.NameToken; if (ident.IsMissing) { yield break; } var diag = CheckDocAttribute(node.Attributes, ident.Location, $"Public {type} {ident} is undocumented"); if (diag != null) { yield return(node, diag); } }
public static GraphNode ToGraphNode(FunctionDeclarationNode node) { var root = new GraphNode(node.GetHashCode(), "\"def " + node.Name.Representation + "\""); root.AddProperty("color", "indianred"); root.AddProperty("tooltip", nameof(FunctionDeclarationNode)); var parameters = new GraphNode(node.Parameters.GetHashCode(), "\"param\""); parameters.AddProperty("tooltip", "parameters"); foreach (var parameter in node.Parameters) { var paramNode = new GraphNode(parameter.GetHashCode(), parameter.Representation); paramNode.AddProperty("tooltip", "parameter"); paramNode.AddProperty("color", "lightgrey"); parameters.AddNode(paramNode); } root.AddNode(parameters); var body = ToGraphNode(node.Value); body.AddProperty("tooltip", "body"); root.AddNode(body); return(root); }
private FunctionDeclarationNode BuildFunctionDeclarationNode( LexSpan lFunc, LexSpan ident, LexSpan lPar, SyntaxNodeOrToken parameters, LexSpan rPar, SyntaxNodeOrToken type, SyntaxNodeOrToken body, LexSpan end, LexSpan rFunc) { var exp = new FunctionDeclarationNode(); exp.AddNode(new FunctionToken(lFunc)); exp.AddNode(new IdentToken(ident)); exp.AddNode(new ParenToken(lPar)); exp.AddNode(parameters); exp.AddNode(new ParenToken(rPar)); exp.AddNode(type); exp.AddNode(body); exp.AddNode(new EndToken(end)); exp.AddNode(new FunctionToken(rFunc)); return(exp); }
public override string VisitFunctionDeclaration(FunctionDeclarationNode faDeclarationNode) { var str = ""; var procedureDeclaration = faDeclarationNode; //var str = $"{AddSpaces()}public void {procedureDeclaration.ProcedureId}\r\n"; // str += AddSpaces() + "{\r\n"; var symbols = procedureDeclaration.Annotations["SymbolTable"] as ScopedSymbolTable; current = symbols; var param = CreateParameters(procedureDeclaration, symbols); var type = typesConverter.GetTypeName(procedureDeclaration.ReturnType.TypeValue); if (procedureDeclaration.Annotations.ContainsKey("Nested")) { str += $"{AddSpaces()}{type} {procedureDeclaration.FunctionName}({param})\r\n"; } else { str += $"{AddSpaces()}public static {type} {procedureDeclaration.FunctionName}({param})\r\n"; } //CurrentScope = new ScopedSymbolTable(procedureDeclaration.ProcedureId, CurrentScope); str += VisitBlock(procedureDeclaration.Block); if (procedureDeclaration.Annotations.ContainsKey("Nested")) { //str = str.Remove(str.Length - 2); //str += ";\r\n"; } //CurrentScope = CurrentScope.ParentScope; current = symbols.ParentScope; //str += AddSpaces() + "}\r\n"; return(str); }
public FunctionSymbol(string name, IEnumerable <ParameterSymbol> parameters, TypeSymbol type, FunctionDeclarationNode declaration = null) : base(name) { Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); Type = type ?? throw new ArgumentNullException(nameof(type)); Declaration = declaration; Key = SymbolKey.FromFunction(name, parameters.Select(p => p.Type)); }
public override dynamic Visit(FunctionDeclarationNode node) { EnterScope(node.Scope); node.Statement.Accept(this); ExitScope(); return(null); }
private void InvokeNativeFunction(FunctionDeclarationNode currentFunction) { var nativeArguments = CurrentContextScopeVariables.Select(variable => variable.Value).ToArray(); currentFunction.NativeBody.DynamicInvoke(nativeArguments); CurrentContextScopeVariables.Add(new Variable { Name = "$return", Value = 0 }); }
public FunctionDeclarationNode IsFunctionDeclaration(GeneralDeclarationNode generalDecla) { StackContext.Context.CanDeclareReturn = true; var position = new Token { Row = _parser.CurrentToken.Row, Column = _parser.CurrentToken.Column }; var functionNode = new FunctionDeclarationNode { Identifier = generalDecla, Position = position }; if (!_parser.Utilities.CompareTokenType(TokenType.OpenParenthesis)) { throw new Exception("Open parenthesis expected at row: " + _parser.CurrentToken.Row + " , column: " + _parser.CurrentToken.Column); } _parser.Utilities.NextToken(); List <GeneralDeclarationNode> parameters = new List <GeneralDeclarationNode>(); ParameterList(parameters); functionNode.Parameters = parameters; if (!_parser.Utilities.CompareTokenType(TokenType.CloseParenthesis)) { throw new Exception("Close parenthesis expected at row: " + _parser.CurrentToken.Row + " , column: " + _parser.CurrentToken.Column); } _parser.Utilities.NextToken(); if (_parser.Utilities.CompareTokenType(TokenType.OpenCurlyBracket)) { _parser.Utilities.NextToken(); var sentences = _parser.ListOfSpecialSentences(); functionNode.Sentences = sentences; } if (_parser.Utilities.CompareTokenType(TokenType.CloseCurlyBracket)) { _parser.Utilities.NextToken(); } else { throw new Exception("Close function body symbol expected at row: " + _parser.CurrentToken.Row + " , column: " + _parser.CurrentToken.Column); } functionNode.Position = _parser.CurrentToken; StackContext.Context.CanDeclareReturn = false; return(functionNode); }
public void Visit(Node node) { if (node is ClassDeclarationNode) { VisitSubnodes(node); } else if (node is CodeBlock) { VisitSubnodes(node); } else if (node is ExpressionNode) { throw new System.Exception("Expression is not valid outside function body."); } else if (node is ForNode) { throw new System.Exception("For Statement is not valid outside function body."); } else if (node is FunctionCallNode) { throw new System.Exception("Function Call is not valid outside function body."); } else if (node is FunctionDeclarationNode) { FunctionDeclarationNode funcDecl = (FunctionDeclarationNode)node; symbolTable.AddSymbol(funcDecl.Name); FunctionVisitor visitor = new FunctionVisitor(symbolTable); symbolTable.BeginScope(); foreach (string param in funcDecl.Parameters) { symbolTable.AddSymbol(param); } visitor.Visit(funcDecl.Children[0]); symbolTable.EndScope(); } else if (node is IfNode) { throw new System.Exception("If Statement is not valid outside function body."); } else if (node is ReturnNode) { throw new System.Exception("Return Statement is not valid outside function body."); } else if (node is ScopeNode) { VisitSubnodes(node); } else if (node is WhileNode) { throw new System.Exception("While Statement is not valid outside function body."); } }
public IEnumerable <StatementNode> Visit(FunctionDeclarationNode node) { IEnumerable <StatementNode> output = new List <StatementNode>(); foreach (var param in node.Parameters) { if (param.HasDefaultValue) { output = output.Concat(Flatten(param.DefaultValue !)); } } return(output.Concat(Visit(node.Body)).Append(node)); }
public void DefineFunction(string functionName, Delegate functionReference) { var metaFunction = new FunctionDeclarationNode(functionName); var parameters = functionReference.Method.GetParameters(); foreach (var parameter in parameters) { var nativeParameterType = GetNativeType(parameter.ParameterType); metaFunction.AddParameter(new ParameterDeclarationNode(nativeParameterType, parameter.Name)); } metaFunction.BodyType = FunctionBodyType.Native; metaFunction.NativeBody = functionReference; Functions.Add(metaFunction); }
private static void Walk([NotNull] Agent agent, [NotNull] FunctionDeclarationNode functionDeclaration, bool isStrict) { if (functionDeclaration.Async) { WalkAsyncFunction(agent, functionDeclaration.Id, functionDeclaration.Parameters, functionDeclaration.Body, isStrict || new FunctionNode(functionDeclaration.Body).IsStrict); } else if (functionDeclaration.Generator) { WalkGeneratorFunction(agent, functionDeclaration.Id, functionDeclaration.Parameters, functionDeclaration.Body, isStrict || new FunctionNode(functionDeclaration.Body).IsStrict); } else { WalkFunction(agent, functionDeclaration.Id, functionDeclaration.Parameters, functionDeclaration.Body, isStrict || new FunctionNode(functionDeclaration.Body).IsStrict); } }
public override dynamic Visit(FunctionDeclarationNode node) { var functionVisitor = new CfgVisitor(CurrentScope, _result); functionVisitor.Visit((StatementListNode)node.Statement); var cfg = new CFG { Blocks = functionVisitor._blocks, Function = node.Function }; _result.Add(cfg); //node.Statement.Accept(this); return(null); }
private GSharpMethod CompileMethod(FunctionDeclarationNode funcDecl, bool isInstanceMethod) { symbolTable.CurrentScope = symbolTable.CurrentScope.ChildScopes[currentScope++]; GSharpMethod methodBuilder = new GSharpMethod(funcDecl.Name, funcDecl.Parameters.Count, symbolTable.CurrentScope.SymbolCount, module); FunctionCompiler compiler = new FunctionCompiler(symbolTable, methodBuilder); for (int i = 0; i < funcDecl.Parameters.Count; i++) { methodBuilder.Parameters[funcDecl.Parameters[i]] = symbolTable.GetSymbol(funcDecl.Parameters[i]).Index; } methodBuilder.IsInstanceMethod = isInstanceMethod; compiler.Visit(funcDecl.Children[0]); symbolTable.CurrentScope = symbolTable.CurrentScope.ParentScope; methodBuilder.EmitInstruction(OperationCode.LoadNull); methodBuilder.FinalizeLabels(); return(methodBuilder); }
public override dynamic Visit(FunctionDeclarationNode node) { EnterScope(node.Statement.Scope); FunctionStack.Push(node); foreach (var par in node.Parameters) { par.Accept(this); } // node.Parameters.ForEach(p => p.Accept(this)); node.Statement.Accept(this); FunctionStack.Pop(); ExitScope(); var type = node.Type.Accept(this); return(type); }
internal Function(Module module, FunctionDeclarationNode node) : base(module, node) { var parms = ImmutableArray <Parameter> .Empty; var treeParams = ImmutableArray <TreeParameter> .Empty; var treeVariadic = (TreeVariadicParameter?)null; var syms = ImmutableArray <(SyntaxSymbol, TreeVariable)> .Empty; var i = 0; foreach (var param in node.ParameterList.Parameters.Nodes) { var name = param.NameToken.Text; var variadic = param.DotDotToken != null; parms = parms.Add(new Parameter(this, param.Attributes, name, i, variadic)); TreeVariable variable; if (!variadic) { var p = new TreeParameter(name); variable = p; treeParams = treeParams.Add(p); } else { variable = treeVariadic = new TreeVariadicParameter(name); } syms = syms.Add((param.GetAnnotation <SyntaxSymbol>("Symbol"), variable)); i++; } Parameters = parms; Tree = new TreeContext(module.Loader, this, treeParams, treeVariadic, ImmutableArray <TreeUpvalue> .Empty); _lowerer = new SyntaxTreeLowerer(module.Loader, Tree, node.Body, node.GetAnnotation <ImmutableHashSet <SyntaxSymbol> >("Freezes")); foreach (var(sym, variable) in syms) { _lowerer.AddVariable(sym, variable); } }
/// <summary> /// 函数定义 /// </summary> /// <param name="node"></param> public void Visit(FunctionDeclarationNode node) { var builder = new StringBuilder(); builder.Append("函数定义:"); builder.AppendFormat(" 函数名称:{0}\n", node.FunctionName); builder.Append(" 函数参数:"); foreach (var item in node.Parameters) { builder.Append(item); } builder.AppendLine(" 函数体:"); Console.WriteLine(builder.ToString()); foreach (var item in node.SubNodes) { Visit((Object)item); } }
public override void Visit(FunctionDeclarationNode node) { var scope = PushFunctionScope(); foreach (var param in node.ParameterList.Parameters.Nodes) { var name = param.NameToken; if (name.IsMissing) { continue; } _scope.Define(SyntaxSymbolKind.Immutable, null, param, name.Text); var duplicate = false; foreach (var param2 in node.ParameterList.Parameters.Nodes) { if (param2 != param && param2.NameToken.Text == name.Text) { duplicate = true; break; } } if (!duplicate) { continue; } Error(param, SyntaxDiagnosticKind.DuplicateParameter, name.Location, $"Function parameter '{name}' (of '{node.NameToken}') declared multiple times"); } base.Visit(node); node.SetAnnotation("Freezes", scope.GetFreezes()); PopScope(); }
public void FunctionDeclarationNoParametersWithReturnTest() { const string Code = @" Func HelloWorld() As Int { Output(""Hello "" + x); } "; FunctionDeclarationNode func = MyAssert.NoError(() => { var lexemes = new Lexer(Code).LexAll(); var parser = new ProgramParser(lexemes, Code); return(parser.ParseFunctionDeclaration()); }); Assert.NotNull(func); Assert.AreEqual("HelloWorld", func !.Identifier); Assert.AreEqual(0, func.ParameterNodes.Count); Assert.NotNull(func.ReturnTypeNode); Assert.AreEqual(1, func.BodyNode.Count); }
internal Module(ModuleLoader loader, ModulePath path, ProgramNode node) : base(node.Attributes) { Loader = loader; Path = path; var decls = ImmutableArray <Declaration> .Empty; foreach (var decl in node.Declarations) { if (decl is UseDeclarationNode) { continue; } decls = decls.Add(decl switch { ConstantDeclarationNode c => (Declaration) new Constant(this, c), FunctionDeclarationNode f => new Function(this, f), ExternalDeclarationNode e => new External(this, e), TestDeclarationNode t => new Test(this, t), _ => throw DebugAssert.Unreachable(), });
public virtual T VisitFunctionDeclaration(FunctionDeclarationNode faDeclarationNode) { throw new NotImplementedException(); }
public ProgramNode ParseToAst() { _scopes.Push(new ProgramNode()); while (!EndOfProgram) { var upcomingToken = PeekNextToken(); if (upcomingToken is KeywordToken) { var keyword = (KeywordToken)NextToken(); var globalScope = _scopes.Count == 1; // There are constraints to what is available on the global scope if (keyword.IsTypeKeyword) { var varType = keyword.ToVariableType(); //it must be followed by a identifier: var name = ReadNextToken <IdentifierToken>(); //so see what it is (function or variable): Token lookahead = PeekNextToken(); if (lookahead is OperatorToken && (((OperatorToken)lookahead).OperatorType == OperatorType.Assignment) || lookahead is StatementSeparatorToken) //variable declaration { if (lookahead is OperatorToken) { NextToken(); //skip the "=" } _currentScope.AddStatement(new VariableDeclarationNode(varType, name.Content, ExpressionNode.CreateFromTokens(ReadUntilStatementSeparator()))); } else if (lookahead is OpenBraceToken) { var lookaheadOpenBrace = lookahead as OpenBraceToken; if (lookaheadOpenBrace.BraceType == BraceType.Square) //It is a list type declaration { //Ensure that the next token is the close square brace NextToken(); //Go past the opening token var secondLookahead = PeekNextToken(); if (secondLookahead is CloseBraceToken && ((CloseBraceToken)secondLookahead).BraceType == BraceType.Square) { NextToken(); //Good, it matched, now skip that too //Add a list declaration node _currentScope.AddStatement(new ListDeclarationNode(varType, name.Content, ExpressionNode.CreateFromTokens(ReadUntilStatementSeparator()))); } else { throw new UnexpectedTokenException("Missing close square bracket in array declaration"); } } //If in the global scope, it can also be a function declaration else if (globalScope && lookaheadOpenBrace.BraceType == BraceType.Round) //function definition { var func = new FunctionDeclarationNode(name.Content); _currentScope.AddStatement(func); //add the function to the old (root) scope... _scopes.Push(func); //...and set it a the new scope! //Read the argument list NextToken(); //skip the opening brace while (!(PeekNextToken() is CloseBraceToken && ((CloseBraceToken)PeekNextToken()).BraceType == BraceType.Round)) //TODO: Refactor using readUntilClosingBrace? { var argType = ReadNextToken <KeywordToken>(); if (!argType.IsTypeKeyword) { throw new ParsingException("Expected type keyword!"); } var argName = ReadNextToken <IdentifierToken>(); func.AddParameter(new ParameterDeclarationNode(argType.ToVariableType(), argName.Content)); if (PeekNextToken() is ArgSeperatorToken) //TODO: Does this allow (int a int b)-style functions? (No arg-seperator!) { NextToken(); //skip the sperator } } NextToken(); //skip the closing brace var curlyBrace = ReadNextToken <OpenBraceToken>(); if (curlyBrace.BraceType != BraceType.Curly) { throw new ParsingException("Wrong brace type found!"); } } } else { throw new Exception("The parser encountered an unexpected token."); } //We can't have anything other than what's listed above on the global scope } //Not a type keyword. If on a local scope, it may be other keywords else if (!globalScope) { switch (keyword.KeywordType) { case KeywordType.Return: _currentScope.AddStatement(new ReturnStatementNode(ExpressionNode.CreateFromTokens(ReadUntilStatementSeparator()))); break; case KeywordType.If: var @if = new IfStatementNode(ExpressionNode.CreateFromTokens(ReadUntilClosingBrace(true))); _currentScope.AddStatement(@if); //Add if statement to previous scope _scopes.Push(@if); //...and set it a the new scope! NextToken(); //skip the opening curly brace break; case KeywordType.While: var @while = new WhileLoopNode(ExpressionNode.CreateFromTokens(ReadUntilClosingBrace(true))); _currentScope.AddStatement(@while); _scopes.Push(@while); NextToken(); //skip the opening curly brace break; default: throw new ParsingException("Unexpected keyword type."); } } else //It was not a keyword, and it was a global scope { throw new ParsingException("Found non-type keyword on global scope."); } } else if (upcomingToken is IdentifierToken && _scopes.Count > 1) //in a nested scope { var identifierToken = upcomingToken as IdentifierToken; NextToken(); //Step past the identifier token var nextToken = PeekNextToken(); //Read the next token if (nextToken is OperatorToken && ((OperatorToken)nextToken).OperatorType == OperatorType.Assignment) //variable assignment { NextToken(); //skip the "=" _currentScope.AddStatement(new VariableAssignmentNode(identifierToken.Content, ExpressionNode.CreateFromTokens(ReadUntilStatementSeparator()))); } else if (nextToken is MemberAccessToken) { List <MemberAccessToken> memberAccessTokens = new List <MemberAccessToken>(); Token currentTestToken; while ((currentTestToken = PeekNextToken()) is MemberAccessToken) //They can be stacked { NextToken(); //Advance memberAccessTokens.Add(currentTestToken as MemberAccessToken); } if (currentTestToken is OperatorToken && ((OperatorToken)currentTestToken).OperatorType == OperatorType.Assignment) //table member assignment { NextToken(); //skip the "=" //Tokens until statement end have to be preloaded as a 'temporary workaround' to allow looking forward var expressionTokens = ReadUntilStatementSeparator().ToList(); _currentScope.AddStatement(new TableAssignmentNode(TableQualifier.Create(identifierToken, memberAccessTokens), ExpressionNode.CreateFromTokens(expressionTokens))); } else if (currentTestToken is OpenBraceToken && ((OpenBraceToken)currentTestToken).BraceType == BraceType.Round) { //Member invocation var fakeIdentifierToken = new IdentifierToken(identifierToken.Content); //So it will be parsed as a function call var memberInvocationInternalFunctionCall = ExpressionNode.CreateFromTokens(new[] { fakeIdentifierToken }.Concat(ReadUntilStatementSeparator())) as FunctionCallExpressionNode; _currentScope.AddStatement(new TableMemberInvocationNode(TableQualifier.Create(identifierToken, memberAccessTokens), memberInvocationInternalFunctionCall.Arguments)); } } else //lone expression (incl. function calls!) { _currentScope.AddStatement(ExpressionNode.CreateFromTokens(new[] { identifierToken }.Concat(ReadUntilStatementSeparator()))); //don't forget the name here! } } else if (upcomingToken is CloseBraceToken) { //Closing a scope var brace = ReadNextToken <CloseBraceToken>(); if (brace.BraceType != BraceType.Curly) { throw new ParsingException("Wrong brace type found!"); } _scopes.Pop(); //Scope has been closed! } else { throw new UnexpectedTokenException("The parser ran into an unexpected token", upcomingToken); } } if (_scopes.Count != 1) { throw new ParsingException("The scopes are not correctly nested."); } return((ProgramNode)_scopes.Pop()); }
public override void Visit(ProgramNode node) { _path = CreatePath(node.Path); foreach (var decl in node.Declarations) { if (!(decl is UseDeclarationNode use)) { continue; } var path = CreateCorrectPath(use.Path); if (path == null) { continue; } if (use.Alias is UseDeclarationAliasNode alias && !alias.NameToken.IsMissing) { var name = alias.NameToken; var duplicate = false; foreach (var decl2 in node.Declarations) { if (decl2 is UseDeclarationNode use2 && use2.Alias is UseDeclarationAliasNode alias2 && alias2 != alias && alias2.NameToken.Text == name.Text) { duplicate = true; break; } } if (!duplicate) { _aliases.Add(name.Text, path); } else { Error(alias, SyntaxDiagnosticKind.DuplicateUseDeclarationAlias, name.Location, $"Module alias '{name}' declared multiple times"); } } if (!(LoadModule(use, use.Path.ComponentTokens.Tokens[0].Location, path) is Module mod)) { continue; } // Don't import symbols if the module is aliased. if (use.Alias != null) { continue; } foreach (var mdecl in mod.Declarations) { if (!mdecl.IsPublic) { continue; } var sym = mdecl switch { Constant _ => SyntaxSymbolKind.Constant, Function _ => SyntaxSymbolKind.Function, External _ => SyntaxSymbolKind.External, _ => (SyntaxSymbolKind?)null, }; if (sym is SyntaxSymbolKind kind) { _scope.Define(kind, path, null, mdecl.Name); } } } foreach (var decl in node.Declarations) { if (!(decl is NamedDeclarationNode named) || decl is MissingNamedDeclarationNode) { continue; } var name = named.NameToken; if (name.IsMissing) { continue; } if (name.Text.StartsWith('_')) { Error(named, SyntaxDiagnosticKind.InvalidDeclarationName, name.Location, $"Declaration '{name}' is invalid; declaration names cannot start with '_'"); continue; } var duplicate = false; foreach (var decl2 in node.Declarations) { if (decl2 == decl || !(decl2 is NamedDeclarationNode named2) || decl2 is MissingNamedDeclarationNode) { continue; } var name2 = named2.NameToken; if (name2.Text != name.Text) { continue; } duplicate = true; } if (duplicate) { Error(named, SyntaxDiagnosticKind.DuplicateDeclaration, name.Location, $"Declaration name '{name}' declared multiple times"); continue; } var sym = decl switch { ConstantDeclarationNode _ => SyntaxSymbolKind.Constant, FunctionDeclarationNode _ => SyntaxSymbolKind.Function, ExternalDeclarationNode _ => SyntaxSymbolKind.External, _ => (SyntaxSymbolKind?)null, }; if (sym is SyntaxSymbolKind kind) { _scope.Define(kind, _path, decl, name.Text); } } foreach (var decl in node.Declarations) { if (!(decl is TestDeclarationNode test)) { continue; } var name = test.NameToken; if (name.Text.StartsWith('_')) { Error(test, SyntaxDiagnosticKind.InvalidDeclarationName, name.Location, $"Test name '{name}' is invalid; test names cannot start with '_'"); continue; } var duplicate = false; foreach (var decl2 in node.Declarations) { if (decl2 != decl && decl2 is TestDeclarationNode test2 && test2.NameToken.Text == name.Text) { duplicate = true; break; } } if (duplicate) { Error(test, SyntaxDiagnosticKind.DuplicateDeclaration, name.Location, $"Test '{name}' declared multiple times"); continue; } } base.Visit(node); }
public string Visit(FunctionDeclarationNode node) { var output = ASTHelper.PrintToken(node.Token) + ASTHelper.PrintToken(node.Name) + ASTHelper.PrintToken(node.OpeningParenthesis);
public string VisitFunctionDeclaration(FunctionDeclarationNode faDeclarationNode) { throw new NotImplementedException(); }
public abstract dynamic Visit(FunctionDeclarationNode node);
public ProgramNode ParseToAst() { scopes.Push(new ProgramNode()); while (!eof()) { if (peek() is KeywordToken) { var keyword = (KeywordToken)next(); if (scopes.Count == 1) //we are a top level, the only valid keywords are variable types, starting a variable or function definition { if (keyword.IsTypeKeyword) { var varType = keyword.ToVariableType(); //it must be followed by a identifier: var name = readToken <IdentifierToken>(); //so see what it is (function or variable): Token lookahead = peek(); if (lookahead is OperatorToken && (((OperatorToken)lookahead).OperatorType == OperatorType.Assignment) || lookahead is StatementSperatorToken) //variable declaration { if (lookahead is OperatorToken) { next(); //skip the "=" } scopes.Peek().AddStatement(new VariableDeclarationNode(varType, name.Content, ExpressionNode.CreateFromTokens(readUntilStatementSeperator()))); } else if (lookahead is OpenBraceToken && (((OpenBraceToken)lookahead).BraceType == BraceType.Round)) //function definition { var func = new FunctionDeclarationNode(name.Content); scopes.Peek().AddStatement(func); //add the function to the old (root) scope... scopes.Push(func); //...and set it a the new scope! //Read the argument list next(); //skip the opening brace while (!(peek() is CloseBraceToken && ((CloseBraceToken)peek()).BraceType == BraceType.Round)) //TODO: Refactor using readUntilClosingBrace? { var argType = readToken <KeywordToken>(); if (!argType.IsTypeKeyword) { throw new ParsingException("Expected type keyword!"); } var argName = readToken <IdentifierToken>(); func.AddParameter(new ParameterDeclarationNode(argType.ToVariableType(), argName.Content)); if (peek() is ArgSeperatorToken) //TODO: Does this allow (int a int b)-style functions? (No arg-seperator!) { next(); //skip the sperator } } next(); //skip the closing brace var curlyBrace = readToken <OpenBraceToken>(); if (curlyBrace.BraceType != BraceType.Curly) { throw new ParsingException("Wrong brace type found!"); } } else { throw new Exception("The parser encountered an unexpected token."); } } else { throw new ParsingException("Found non-type keyword on top level."); } } else //we are in a nested scope { //TODO: Can we avoid the code duplication from above? if (keyword.IsTypeKeyword) //local variable declaration! { var varType = keyword.ToVariableType(); //it must be followed by a identifier: var name = readToken <IdentifierToken>(); //so see what it is (function or variable): Token lookahead = peek(); if (lookahead is OperatorToken && (((OperatorToken)lookahead).OperatorType == OperatorType.Assignment) || lookahead is StatementSperatorToken) //variable declaration { if (lookahead is OperatorToken) { next(); //skip the "=" } scopes.Peek().AddStatement(new VariableDeclarationNode(varType, name.Content, ExpressionNode.CreateFromTokens(readUntilStatementSeperator()))); } } else { switch (keyword.KeywordType) { case KeywordType.Return: scopes.Peek().AddStatement(new ReturnStatementNode(ExpressionNode.CreateFromTokens(readUntilStatementSeperator()))); break; case KeywordType.If: var @if = new IfStatementNode(ExpressionNode.CreateFromTokens(readUntilClosingBrace())); scopes.Peek().AddStatement(@if); scopes.Push(@if); break; case KeywordType.While: var @while = new WhileLoopNode(ExpressionNode.CreateFromTokens(readUntilClosingBrace())); scopes.Peek().AddStatement(@while); scopes.Push(@while); break; default: throw new ParsingException("Unexpected keyword type."); } } } } else if (peek() is IdentifierToken && scopes.Count > 1) //in nested scope { var name = readToken <IdentifierToken>(); if (peek() is OperatorToken && ((OperatorToken)peek()).OperatorType == OperatorType.Assignment) //variable assignment { next(); //skip the "=" scopes.Peek().AddStatement(new VariableAssingmentNode(name.Content, ExpressionNode.CreateFromTokens(readUntilStatementSeperator()))); } else //lone expression (incl. function calls!) { scopes.Peek().AddStatement(ExpressionNode.CreateFromTokens(new[] { name }.Concat(readUntilStatementSeperator()))); //don't forget the name here! } } else if (peek() is CloseBraceToken) { var brace = readToken <CloseBraceToken>(); if (brace.BraceType != BraceType.Curly) { throw new ParsingException("Wrong brace type found!"); } scopes.Pop(); //Scope has been closed! } else { throw new ParsingException("The parser ran into an unexpeted token."); } } if (scopes.Count != 1) { throw new ParsingException("The scopes are not correctly nested."); } return((ProgramNode)scopes.Pop()); }
public void Accept(FunctionDeclarationNode node) { // Funcs are lowercase HassiumWarning.EnforceCasing(module, node.SourceLocation, node.Name, HassiumCasingType.Lower); var method = new HassiumMethod(module, node.Name); method.DocStr = node.DocStr; method.IsPrivate = node.IsPrivate; methodStack.Push(method); method.SourceLocation = node.SourceLocation; method.SourceRepresentation = node.ToString(); method.Parent = classStack.Peek(); table.EnterScope(); foreach (var param in node.Parameters) { if (param.FunctionParameterType == FunctionParameterType.Enforced) { methodStack.Push(new HassiumMethod(module)); methodStack.Peek().Parent = classStack.Peek(); param.Type.Visit(this); emit(param.Type.SourceLocation, InstructionType.Return); param.EnforcedType = methodStack.Pop(); } method.Parameters.Add(param, table.AddSymbol(param.Name)); } if (node.Body is CodeBlockNode) { node.Body.VisitChildren(this); } else { node.Body.Visit(this); } if (node.EnforcedReturnType != null) { methodStack.Push(new HassiumMethod(module)); node.EnforcedReturnType.Visit(this); emit(node.EnforcedReturnType.SourceLocation, InstructionType.Return); method.ReturnType = methodStack.Pop(); } table.LeaveScope(); method = methodStack.Pop(); if (classStack.Peek().ContainsAttribute(method.Name)) { var attrib = classStack.Peek().BoundAttributes[method.Name]; if (attrib is HassiumMultiFunc) { (attrib as HassiumMultiFunc).Methods.Add(method); } else { classStack.Peek().BoundAttributes.Remove(method.Name); var multiFunc = new HassiumMultiFunc(); multiFunc.Methods.Add(attrib as HassiumMethod); multiFunc.Methods.Add(method); classStack.Peek().AddAttribute(method.Name, multiFunc); } } else { classStack.Peek().AddAttribute(method.Name, method); } }