diff --git a/example/interop/bindings.nub b/example/interop/bindings.nub index e425923..e164518 100644 --- a/example/interop/bindings.nub +++ b/example/interop/bindings.nub @@ -1,4 +1,4 @@ -module c_interop +namespace c extern func printf(fmt: string, ...args: any) extern func getchar(): i32 diff --git a/example/program.nub b/example/program.nub index 3421d7f..f0478e4 100644 --- a/example/program.nub +++ b/example/program.nub @@ -1,6 +1,4 @@ -import c_interop - -module main +namespace main /// # Documentation /// ## Documentation subtitle diff --git a/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs index d080409..2e24ec3 100644 --- a/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/compiler/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -6,9 +6,8 @@ public class Lexer { private static readonly Dictionary Keywords = new() { + ["namespace"] = Symbol.Namespace, ["func"] = Symbol.Func, - ["import"] = Symbol.Import, - ["module"] = Symbol.Module, ["if"] = Symbol.If, ["else"] = Symbol.Else, ["while"] = Symbol.While, @@ -31,6 +30,7 @@ public class Lexer [['!', '=']] = Symbol.NotEqual, [['<', '=']] = Symbol.LessThanOrEqual, [['>', '=']] = Symbol.GreaterThanOrEqual, + [[':', ':']] = Symbol.DoubleColon, }; private static readonly Dictionary Chars = new() diff --git a/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs b/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs index dc063f9..c5cd882 100644 --- a/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs +++ b/src/compiler/Nub.Lang/Frontend/Lexing/SymbolToken.cs @@ -9,8 +9,6 @@ public class SymbolToken(SourceText sourceText, int startIndex, int endIndex, Sy public enum Symbol { - Import, - Module, Func, Return, If, @@ -44,4 +42,6 @@ public enum Symbol Struct, Caret, Ampersand, + DoubleColon, + Namespace, } \ No newline at end of file diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs b/src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs index e5e8e85..8ee470e 100644 --- a/src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs +++ b/src/compiler/Nub.Lang/Frontend/Parsing/FuncCall.cs @@ -1,7 +1,8 @@ namespace Nub.Lang.Frontend.Parsing; -public class FuncCall(string name, List parameters) +public class FuncCall(string @namespace, string name, List parameters) { + public string Namespace { get; } = @namespace; public string Name { get; } = name; public List Parameters { get; } = parameters; diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs index f198e35..9f53ce4 100644 --- a/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/compiler/Nub.Lang/Frontend/Parsing/Parser.cs @@ -9,24 +9,19 @@ public class Parser private List _diagnostics = []; private List _tokens = []; private int _index; + private string _namespace = string.Empty; public DiagnosticsResult ParseModule(List tokens) { _diagnostics = []; _tokens = tokens; _index = 0; + _namespace = string.Empty; try { - List imports = []; - while (TryExpectSymbol(Symbol.Import)) - { - var name = ExpectIdentifier(); - imports.Add(name.Value); - } - - ExpectSymbol(Symbol.Module); - var module = ExpectIdentifier().Value; + ExpectSymbol(Symbol.Namespace); + _namespace = ExpectIdentifier().Value; List definitions = []; @@ -34,8 +29,8 @@ public class Parser { definitions.Add(ParseDefinition()); } - - return new DiagnosticsResult(_diagnostics, new SourceFile(module, imports, definitions)); + + return new DiagnosticsResult(_diagnostics, new SourceFile(_namespace, definitions)); } catch (ParseException ex) { @@ -187,41 +182,7 @@ public class Parser { case IdentifierToken identifier: { - var symbol = ExpectSymbol(); - switch (symbol.Symbol) - { - case Symbol.OpenParen: - { - var parameters = new List(); - while (!TryExpectSymbol(Symbol.CloseParen)) - { - parameters.Add(ParseExpression()); - TryExpectSymbol(Symbol.Comma); - } - - return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, parameters)); - } - case Symbol.Assign: - { - var value = ParseExpression(); - return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, Optional.Empty(), value); - } - case Symbol.Colon: - { - var type = ParseType(); - ExpectSymbol(Symbol.Assign); - var value = ParseExpression(); - return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, type, value); - } - default: - { - throw new ParseException(Diagnostic - .Error($"Unexpected symbol '{symbol.Symbol}' after identifier") - .WithHelp("Expected '(', '=', or ':' after identifier") - .At(symbol) - .Build()); - } - } + return ParseStatementIdentifier(startIndex, identifier); } case SymbolToken symbol: { @@ -250,6 +211,72 @@ public class Parser } } + private StatementNode ParseStatementIdentifier(int startIndex, IdentifierToken identifier) + { + var symbol = ExpectSymbol(); + switch (symbol.Symbol) + { + case Symbol.DoubleColon: + { + var name = ExpectIdentifier(); + ExpectSymbol(Symbol.OpenParen); + var parameters = new List(); + while (!TryExpectSymbol(Symbol.CloseParen)) + { + parameters.Add(ParseExpression()); + if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + { + _diagnostics.Add(Diagnostic + .Warning("Missing comma between function arguments") + .WithHelp("Add a ',' to separate arguments") + .At(nextToken) + .Build()); + } + } + + return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, name.Value, parameters)); + } + case Symbol.OpenParen: + { + var parameters = new List(); + while (!TryExpectSymbol(Symbol.CloseParen)) + { + parameters.Add(ParseExpression()); + if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + { + _diagnostics.Add(Diagnostic + .Warning("Missing comma between function arguments") + .WithHelp("Add a ',' to separate arguments") + .At(nextToken) + .Build()); + } + } + + return new FuncCallStatementNode(GetTokensForNode(startIndex), new FuncCall(_namespace, identifier.Value, parameters)); + } + case Symbol.Assign: + { + var value = ParseExpression(); + return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, Optional.Empty(), value); + } + case Symbol.Colon: + { + var type = ParseType(); + ExpectSymbol(Symbol.Assign); + var value = ParseExpression(); + return new VariableAssignmentNode(GetTokensForNode(startIndex), identifier.Value, type, value); + } + default: + { + throw new ParseException(Diagnostic + .Error($"Unexpected symbol '{symbol.Symbol}' after identifier") + .WithHelp("Expected '(', '=', or ':' after identifier") + .At(symbol) + .Build()); + } + } + } + private ReturnNode ParseReturn(int startIndex) { var value = Optional.Empty(); @@ -384,10 +411,11 @@ public class Parser var next = Peek(); switch (next.Value) { - case SymbolToken { Symbol: Symbol.OpenParen }: + case SymbolToken { Symbol: Symbol.DoubleColon }: { - Next(); - List parameters = []; + var name = ExpectIdentifier(); + ExpectSymbol(Symbol.OpenParen); + var parameters = new List(); while (!TryExpectSymbol(Symbol.CloseParen)) { parameters.Add(ParseExpression()); @@ -401,7 +429,26 @@ public class Parser } } - expr = new FuncCallExpressionNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, parameters)); + expr = new FuncCallExpressionNode(GetTokensForNode(startIndex), new FuncCall(identifier.Value, name.Value, parameters)); + break; + } + case SymbolToken { Symbol: Symbol.OpenParen }: + { + var parameters = new List(); + while (!TryExpectSymbol(Symbol.CloseParen)) + { + parameters.Add(ParseExpression()); + if (!TryExpectSymbol(Symbol.Comma) && Peek().TryGetValue(out var nextToken) && nextToken is not SymbolToken { Symbol: Symbol.CloseParen }) + { + _diagnostics.Add(Diagnostic + .Warning("Missing comma between function arguments") + .WithHelp("Add a ',' to separate arguments") + .At(nextToken) + .Build()); + } + } + + expr = new FuncCallExpressionNode(GetTokensForNode(startIndex), new FuncCall(_namespace, identifier.Value, parameters)); break; } default: diff --git a/src/compiler/Nub.Lang/Frontend/Parsing/SourceFile.cs b/src/compiler/Nub.Lang/Frontend/Parsing/SourceFile.cs index 0f9642a..4849a8e 100644 --- a/src/compiler/Nub.Lang/Frontend/Parsing/SourceFile.cs +++ b/src/compiler/Nub.Lang/Frontend/Parsing/SourceFile.cs @@ -1,8 +1,7 @@ namespace Nub.Lang.Frontend.Parsing; -public class SourceFile(string module, List imports, List definitions) +public class SourceFile(string @namespace, List definitions) { - public string Module { get; } = module; - public List Imports { get; } = imports; + public string Namespace { get; } = @namespace; public List Definitions { get; } = definitions; } \ No newline at end of file