directory scoped imports
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
8
Nub.Lang/Nub.Lang/Frontend/Parsing/ModuleNode.cs
Normal file
8
Nub.Lang/Nub.Lang/Frontend/Parsing/ModuleNode.cs
Normal 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;
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
0
Nub.Lang/Nub.Lang/output/build.sh
Normal file → Executable file
Reference in New Issue
Block a user