directory scoped imports

This commit is contained in:
nub31
2025-01-29 20:51:38 +01:00
parent 0c807d765c
commit 88aa2375ef
10 changed files with 69 additions and 68 deletions

6
.gitignore vendored
View File

@@ -33,6 +33,6 @@ Thumbs.db
Desktop.ini Desktop.ini
.DS_Store .DS_Store
Nub.Lang/Nub.Lang/Output/*.o Nub.Lang/Nub.Lang/output/*.o
Nub.Lang/Nub.Lang/Output/out Nub.Lang/Nub.Lang/output/out
Nub.Lang/Nub.Lang/Output/out.asm Nub.Lang/Nub.Lang/output/out.asm

View File

@@ -9,7 +9,7 @@ public class Lexer
["func"] = Symbol.Func, ["func"] = Symbol.Func,
["extern"] = Symbol.Extern, ["extern"] = Symbol.Extern,
["return"] = Symbol.Return, ["return"] = Symbol.Return,
["include"] = Symbol.Include, ["import"] = Symbol.Import,
["let"] = Symbol.Let, ["let"] = Symbol.Let,
["if"] = Symbol.If, ["if"] = Symbol.If,
["else"] = Symbol.Else, ["else"] = Symbol.Else,
@@ -45,17 +45,14 @@ public class Lexer
['!'] = Symbol.Bang, ['!'] = Symbol.Bang,
}; };
private readonly string _src; private string _src = string.Empty;
private int _index; private int _index;
public Lexer(string src) public IReadOnlyCollection<Token> Lex(string src)
{ {
_src = src; _src = src;
}
public IReadOnlyCollection<Token> Lex()
{
_index = 0; _index = 0;
List<Token> tokens = []; List<Token> tokens = [];
while (Peek().HasValue) while (Peek().HasValue)
{ {

View File

@@ -8,7 +8,7 @@ public class SymbolToken(Symbol symbol) : Token
public enum Symbol public enum Symbol
{ {
Whitespace, Whitespace,
Include, Import,
Extern, Extern,
Func, Func,
Return, Return,

View File

@@ -1,7 +0,0 @@
namespace Nub.Lang.Frontend.Parsing;
public class FileNode(IReadOnlyCollection<string> includes, IReadOnlyCollection<DefinitionNode> definitions) : Node
{
public IReadOnlyCollection<string> Includes { get; } = includes;
public IReadOnlyCollection<DefinitionNode> Definitions { get; } = definitions;
}

View File

@@ -0,0 +1,8 @@
namespace Nub.Lang.Frontend.Parsing;
public class ModuleNode(string path, IReadOnlyCollection<string> imports, IReadOnlyCollection<DefinitionNode> definitions) : Node
{
public string Path { get; } = path;
public IReadOnlyCollection<string> Imports { get; } = imports;
public IReadOnlyCollection<DefinitionNode> Definitions { get; } = definitions;
}

View File

@@ -6,38 +6,37 @@ namespace Nub.Lang.Frontend.Parsing;
public class Parser public class Parser
{ {
private readonly Token[] _tokens; private IReadOnlyCollection<Token> _tokens = [];
private int _index; private int _index;
public Parser(IReadOnlyCollection<Token> tokens) public ModuleNode ParseModule(IReadOnlyCollection<Token> tokens, string path)
{
_tokens = tokens.ToArray();
}
public FileNode ParseFile(string relativePath)
{ {
_index = 0; _index = 0;
_tokens = tokens;
List<DefinitionNode> definitions = []; List<DefinitionNode> definitions = [];
List<string> includes = []; List<string> imports = [];
while (TryExpectSymbol(Symbol.Include))
{
var name = ExpectLiteral();
if (name.Type is not StringType)
{
throw new Exception("Using statements must have a string literal value");
}
TryExpectSymbol(Symbol.Semicolon);
includes.Add(name.Value);
}
while (Peek().HasValue) while (Peek().HasValue)
{ {
definitions.Add(ParseDefinition()); if (TryExpectSymbol(Symbol.Import))
{
var name = ExpectLiteral();
if (name.Type is not StringType)
{
throw new Exception("Import statements must have a string literal value");
}
TryExpectSymbol(Symbol.Semicolon);
imports.Add(name.Value);
}
else
{
definitions.Add(ParseDefinition());
}
} }
return new FileNode(includes, definitions); return new ModuleNode(path, imports, definitions);
} }
private DefinitionNode ParseDefinition() private DefinitionNode ParseDefinition()
@@ -450,14 +449,14 @@ public class Parser
private Optional<Token> Peek() private Optional<Token> Peek()
{ {
while (_index < _tokens.Length && _tokens[_index] is SymbolToken { Symbol: Symbol.Whitespace }) while (_index < _tokens.Count && _tokens.ElementAt(_index) is SymbolToken { Symbol: Symbol.Whitespace })
{ {
Next(); Next();
} }
if (_index < _tokens.Length) if (_index < _tokens.Count)
{ {
return _tokens[_index]; return _tokens.ElementAt(_index);
} }
return Optional<Token>.Empty(); return Optional<Token>.Empty();

View File

@@ -1,39 +1,45 @@
using System.Diagnostics; using Nub.Lang.Backend.Custom;
using Nub.Lang.Backend.Custom;
using Nub.Lang.Frontend.Lexing; using Nub.Lang.Frontend.Lexing;
using Nub.Lang.Frontend.Parsing; using Nub.Lang.Frontend.Parsing;
using Nub.Lang.Frontend.Typing; using Nub.Lang.Frontend.Typing;
var rootPath = Path.GetDirectoryName(args[0]); List<ModuleNode> modules = [];
var rootFileName = Path.GetFileName(args[0]);
Debug.Assert(rootPath != null && rootFileName != null);
Dictionary<string, FileNode> files = []; var lexer = new Lexer();
var parser = new Parser();
Queue<string> queue = []; Parse(args[0]);
queue.Enqueue(rootFileName);
while (queue.TryDequeue(out var path)) void Parse(string path)
{ {
var src = File.ReadAllText(Path.Combine(rootPath, path)); var files = Directory.EnumerateFiles(path, "*.nub", SearchOption.TopDirectoryOnly);
var lexer = new Lexer(src);
var tokens = lexer.Lex();
var parser = new Parser(tokens);
var file = parser.ParseFile(path);
files[path] = file;
foreach (var include in file.Includes) List<Token> tokens = [];
foreach (var file in files)
{ {
if (!files.ContainsKey(include)) var src = File.ReadAllText(file);
tokens.AddRange(lexer.Lex(src));
}
var module = parser.ParseModule(tokens, path);
modules.Add(module);
foreach (var import in module.Imports)
{
var importPath = Path.GetFullPath(import, module.Path);
if (modules.All(m => m.Path != importPath))
{ {
queue.Enqueue(include); Parse(importPath);
} }
} }
} }
var definitions = files.Values.SelectMany(f => f.Definitions).ToArray(); foreach (var moduleNode in modules)
{
Console.WriteLine(moduleNode.Path);
}
var definitions = modules.SelectMany(f => f.Definitions).ToArray();
var typer = new ExpressionTyper(definitions); var typer = new ExpressionTyper(definitions);
typer.Populate(); typer.Populate();

View File

@@ -1,5 +1,3 @@
include "core/strlen.nub"
let SYS_WRITE = 1; let SYS_WRITE = 1;
let STD_OUT = 1; let STD_OUT = 1;
let STD_ERR = 2; let STD_ERR = 2;

View File

@@ -1,4 +1,4 @@
include "core/print.nub"; import "core";
func main() { func main() {
println("test"); println("test");

0
Nub.Lang/Nub.Lang/output/build.sh Normal file → Executable file
View File