Compare commits

..

10 Commits

Author SHA1 Message Date
nub31
0c35bc052c remove attributes 2025-10-23 22:53:07 +02:00
nub31
2641357832 Add server bin to lfs 2025-10-23 22:34:54 +02:00
nub31
9f91e42d63 Clean up cast syntax and rules 2025-10-23 21:39:24 +02:00
nub31
a7c45784b9 Improved nodes 2025-10-23 19:17:51 +02:00
nub31
7486f2fd4e extension working 2025-10-23 18:52:39 +02:00
nub31
6775a09ba9 ... 2025-10-23 18:34:02 +02:00
nub31
0f191b21bc ... 2025-10-23 18:33:51 +02:00
nub31
bfe8b7b18e ... 2025-10-23 18:32:03 +02:00
nub31
db5d444cf2 Output c pane 2025-10-23 18:10:53 +02:00
nub31
08ae39b5ed ,,, 2025-10-23 17:55:45 +02:00
16 changed files with 5213 additions and 612 deletions

View File

@@ -68,368 +68,10 @@ public static class AstExtensions
public static Node? DeepestNodeAtPosition(this CompilationUnit compilationUnit, int line, int character)
{
return compilationUnit.Functions
.SelectMany(x => x.EnumerateDescendantsAndSelf())
.SelectMany(x => x.DescendantsAndSelf())
.Where(n => n.ContainsPosition(line, character))
.OrderBy(n => n.Tokens.First().Span.Start.Line)
.ThenBy(n => n.Tokens.First().Span.Start.Column)
.LastOrDefault();
}
public static Node? DeepestNodeAtPosition(this Node node, int line, int character)
{
return node.EnumerateDescendantsAndSelf()
.Where(n => n.ContainsPosition(line, character))
.OrderBy(n => n.Tokens.First().Span.Start.Line)
.ThenBy(n => n.Tokens.First().Span.Start.Column)
.LastOrDefault();
}
public static IEnumerable<Node> EnumerateDescendantsAndSelf(this Node node)
{
yield return node;
switch (node)
{
case FuncNode func:
{
foreach (var n in func.Prototype.EnumerateDescendantsAndSelf())
{
yield return n;
}
if (func.Body != null)
{
foreach (var n in func.Body.EnumerateDescendantsAndSelf())
{
yield return n;
}
}
break;
}
case FuncPrototypeNode proto:
{
foreach (var n in proto.Parameters.SelectMany(param => param.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case BlockNode block:
{
foreach (var n in block.Statements.SelectMany(stmt => stmt.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case StatementFuncCallNode stmtCall:
{
foreach (var n in stmtCall.FuncCall.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ReturnNode { Value: not null } ret:
{
foreach (var n in ret.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case AssignmentNode assign:
{
foreach (var n in assign.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in assign.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case IfNode ifNode:
{
foreach (var n in ifNode.Condition.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in ifNode.Body.EnumerateDescendantsAndSelf())
{
yield return n;
}
if (ifNode.Else.HasValue)
{
if (ifNode.Else.Value.IsCase1(out var elseIfNode))
{
foreach (var n in elseIfNode.EnumerateDescendantsAndSelf())
{
yield return n;
}
}
else if (ifNode.Else.Value.IsCase2(out var elseNode))
{
foreach (var n in elseNode.EnumerateDescendantsAndSelf())
{
yield return n;
}
}
}
break;
}
case VariableDeclarationNode decl:
{
if (decl.Assignment != null)
{
foreach (var n in decl.Assignment.EnumerateDescendantsAndSelf())
{
yield return n;
}
}
break;
}
case WhileNode whileNode:
{
foreach (var n in whileNode.Condition.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in whileNode.Body.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ForSliceNode forSlice:
{
foreach (var n in forSlice.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in forSlice.Body.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ForConstArrayNode forConst:
{
foreach (var n in forConst.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in forConst.Body.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case DeferNode defer:
{
foreach (var n in defer.Statement.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case BinaryExpressionNode bin:
{
foreach (var n in bin.Left.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in bin.Right.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case UnaryExpressionNode unary:
{
foreach (var n in unary.Operand.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case FuncCallNode call:
{
foreach (var n in call.Expression.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in call.Parameters.SelectMany(param => param.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case ArrayInitializerNode arrInit:
{
foreach (var n in arrInit.Values.SelectMany(val => val.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case ConstArrayInitializerNode constArrInit:
{
foreach (var n in constArrInit.Values.SelectMany(val => val.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case ArrayIndexAccessNode arrIndex:
{
foreach (var n in arrIndex.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in arrIndex.Index.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ConstArrayIndexAccessNode constArrIndex:
{
foreach (var n in constArrIndex.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in constArrIndex.Index.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case SliceIndexAccessNode sliceIndex:
{
foreach (var n in sliceIndex.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
foreach (var n in sliceIndex.Index.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case AddressOfNode addr:
{
foreach (var n in addr.LValue.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case StructFieldAccessNode field:
{
foreach (var n in field.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case StructInitializerNode structInit:
{
foreach (var n in structInit.Initializers.SelectMany(kv => kv.Value.EnumerateDescendantsAndSelf()))
{
yield return n;
}
break;
}
case DereferenceNode deref:
{
foreach (var n in deref.Target.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ConvertIntNode convInt:
{
foreach (var n in convInt.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ConvertFloatNode convFloat:
{
foreach (var n in convFloat.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ConvertCStringToStringNode convStr:
{
foreach (var n in convStr.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case FloatToIntBuiltinNode ftoi:
{
foreach (var n in ftoi.Value.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
case ConstArrayToSliceNode constSlice:
{
foreach (var n in constSlice.Array.EnumerateDescendantsAndSelf())
{
yield return n;
}
break;
}
}
}
}

View File

@@ -150,9 +150,8 @@ internal class CompletionHandler(WorkspaceManager workspaceManager) : Completion
});
}
var variables = function
.Body!
.EnumerateDescendantsAndSelf()
var variables = function.Body!
.Descendants()
.OfType<VariableDeclarationNode>();
foreach (var variable in variables)

View File

@@ -44,7 +44,7 @@ internal class DefinitionHandler(WorkspaceManager workspaceManager) : Definition
}
var variable = function?.Body?
.EnumerateDescendantsAndSelf()
.Descendants()
.OfType<VariableDeclarationNode>()
.FirstOrDefault(x => x.Name == variableIdentifierNode.Name);

View File

@@ -1,12 +1,10 @@
using NubLang.Ast;
using NubLang.Generation;
using NubLang.Syntax;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace NubLang.LSP;
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILanguageServerFacade server)
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher)
{
private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new();
private readonly Dictionary<string, CompilationUnit> _compilationUnits = new();
@@ -29,47 +27,37 @@ public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILangua
_syntaxTrees[path] = parseResult;
}
Generate();
foreach (var (fsPath, syntaxTree) in _syntaxTrees)
{
var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList());
var typeChecker = new TypeChecker(syntaxTree, modules);
var result = typeChecker.Check();
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
_compilationUnits[fsPath] = result;
}
}
public void UpdateFile(DocumentUri path)
{
var fsPath = path.GetFileSystemPath();
var text = File.ReadAllText(fsPath);
var tokenizer = new Tokenizer(fsPath, text);
tokenizer.Tokenize();
diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
var parser = new Parser();
var parseResult = parser.Parse(tokenizer.Tokens);
var syntaxTree = parser.Parse(tokenizer.Tokens);
diagnosticsPublisher.Publish(path, parser.Diagnostics);
_syntaxTrees[fsPath] = syntaxTree;
_syntaxTrees[fsPath] = parseResult;
Generate();
}
private void Generate()
{
var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList());
foreach (var (documentUri, syntaxTree) in _syntaxTrees)
{
var typeChecker = new TypeChecker(syntaxTree, modules);
var result = typeChecker.Check();
diagnosticsPublisher.Publish(documentUri, typeChecker.Diagnostics);
_compilationUnits[documentUri] = result;
var generator = new Generator(result);
var c = generator.Emit();
server.SendNotification("nub/output", new
{
content = c,
uri = documentUri
});
}
var typeChecker = new TypeChecker(syntaxTree, modules);
var result = typeChecker.Check();
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
_compilationUnits[fsPath] = result;
}
public void RemoveFile(DocumentUri path)
@@ -79,11 +67,6 @@ public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher, ILangua
_compilationUnits.Remove(fsPath);
}
public Dictionary<string, CompilationUnit> GetCompilationUnits()
{
return _compilationUnits;
}
public CompilationUnit? GetCompilationUnit(DocumentUri path)
{
return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath());

View File

@@ -2,17 +2,62 @@ using NubLang.Syntax;
namespace NubLang.Ast;
public abstract record Node(List<Token> Tokens);
public abstract record Node(List<Token> Tokens)
{
public abstract IEnumerable<Node> Children();
public IEnumerable<Node> Descendants()
{
foreach (var child in Children())
{
foreach (var descendant in child.DescendantsAndSelf())
{
yield return descendant;
}
}
}
public IEnumerable<Node> DescendantsAndSelf()
{
yield return this;
foreach (var descendant in Descendants())
{
yield return descendant;
}
}
}
#region Definitions
public abstract record DefinitionNode(List<Token> Tokens, string Module, string Name) : Node(Tokens);
public record FuncParameterNode(List<Token> Tokens, string Name, NubType Type) : Node(Tokens);
public record FuncParameterNode(List<Token> Tokens, string Name, NubType Type) : Node(Tokens)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record FuncPrototypeNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens);
public record FuncPrototypeNode(List<Token> Tokens, string Module, string Name, string? ExternSymbol, List<FuncParameterNode> Parameters, NubType ReturnType) : Node(Tokens)
{
public override IEnumerable<Node> Children()
{
return Parameters;
}
}
public record FuncNode(List<Token> Tokens, FuncPrototypeNode Prototype, BlockNode? Body) : DefinitionNode(Tokens, Prototype.Module, Prototype.Name);
public record FuncNode(List<Token> Tokens, FuncPrototypeNode Prototype, BlockNode? Body) : DefinitionNode(Tokens, Prototype.Module, Prototype.Name)
{
public override IEnumerable<Node> Children()
{
yield return Prototype;
if (Body != null)
{
yield return Body;
}
}
}
#endregion
@@ -22,29 +67,110 @@ public abstract record StatementNode(List<Token> Tokens) : Node(Tokens);
public abstract record TerminalStatementNode(List<Token> Tokens) : StatementNode(Tokens);
public record BlockNode(List<Token> Tokens, List<StatementNode> Statements) : StatementNode(Tokens);
public record BlockNode(List<Token> Tokens, List<StatementNode> Statements) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
return Statements;
}
}
public record StatementFuncCallNode(List<Token> Tokens, FuncCallNode FuncCall) : StatementNode(Tokens);
public record StatementFuncCallNode(List<Token> Tokens, FuncCallNode FuncCall) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return FuncCall;
}
}
public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(Tokens);
public record ReturnNode(List<Token> Tokens, ExpressionNode? Value) : TerminalStatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
if (Value != null) yield return Value;
}
}
public record AssignmentNode(List<Token> Tokens, LValueExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens);
public record AssignmentNode(List<Token> Tokens, LValueExpressionNode Target, ExpressionNode Value) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Value;
}
}
public record IfNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body, Variant<IfNode, BlockNode>? Else) : StatementNode(Tokens);
public record IfNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body, Variant<IfNode, BlockNode>? Else) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Condition;
yield return Body;
if (Else.HasValue)
{
yield return Else.Value.Match<Node>(x => x, x => x);
}
}
}
public record VariableDeclarationNode(List<Token> Tokens, string Name, ExpressionNode? Assignment, NubType Type) : StatementNode(Tokens);
public record VariableDeclarationNode(List<Token> Tokens, string Name, ExpressionNode? Assignment, NubType Type) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
if (Assignment != null) yield return Assignment;
}
}
public record ContinueNode(List<Token> Tokens) : TerminalStatementNode(Tokens);
public record ContinueNode(List<Token> Tokens) : TerminalStatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record BreakNode(List<Token> Tokens) : TerminalStatementNode(Tokens);
public record BreakNode(List<Token> Tokens) : TerminalStatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record WhileNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body) : StatementNode(Tokens);
public record WhileNode(List<Token> Tokens, ExpressionNode Condition, BlockNode Body) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Condition;
yield return Body;
}
}
public record ForSliceNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens);
public record ForSliceNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Body;
}
}
public record ForConstArrayNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens);
public record ForConstArrayNode(List<Token> Tokens, string ElementName, string? IndexName, ExpressionNode Target, BlockNode Body) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Body;
}
}
public record DeferNode(List<Token> Tokens, StatementNode Statement) : StatementNode(Tokens);
public record DeferNode(List<Token> Tokens, StatementNode Statement) : StatementNode(Tokens)
{
public override IEnumerable<Node> Children()
{
yield return Statement;
}
}
#endregion
@@ -86,72 +212,255 @@ public abstract record RValueExpressionNode(List<Token> Tokens, NubType Type) :
public abstract record IntermediateExpression(List<Token> Tokens) : ExpressionNode(Tokens, new NubVoidType());
public record StringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubStringType());
public record StringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubStringType())
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record CStringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubCStringType());
public record CStringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubCStringType())
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record I8LiteralNode(List<Token> Tokens, sbyte Value) : RValueExpressionNode(Tokens, new NubIntType(true, 8));
public record I8LiteralNode(List<Token> Tokens, sbyte Value) : RValueExpressionNode(Tokens, new NubIntType(true, 8))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record I16LiteralNode(List<Token> Tokens, short Value) : RValueExpressionNode(Tokens, new NubIntType(true, 16));
public record I16LiteralNode(List<Token> Tokens, short Value) : RValueExpressionNode(Tokens, new NubIntType(true, 16))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record I32LiteralNode(List<Token> Tokens, int Value) : RValueExpressionNode(Tokens, new NubIntType(true, 32));
public record I32LiteralNode(List<Token> Tokens, int Value) : RValueExpressionNode(Tokens, new NubIntType(true, 32))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record I64LiteralNode(List<Token> Tokens, long Value) : RValueExpressionNode(Tokens, new NubIntType(true, 64));
public record I64LiteralNode(List<Token> Tokens, long Value) : RValueExpressionNode(Tokens, new NubIntType(true, 64))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record U8LiteralNode(List<Token> Tokens, byte Value) : RValueExpressionNode(Tokens, new NubIntType(false, 8));
public record U8LiteralNode(List<Token> Tokens, byte Value) : RValueExpressionNode(Tokens, new NubIntType(false, 8))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record U16LiteralNode(List<Token> Tokens, ushort Value) : RValueExpressionNode(Tokens, new NubIntType(false, 16));
public record U16LiteralNode(List<Token> Tokens, ushort Value) : RValueExpressionNode(Tokens, new NubIntType(false, 16))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record U32LiteralNode(List<Token> Tokens, uint Value) : RValueExpressionNode(Tokens, new NubIntType(false, 32));
public record U32LiteralNode(List<Token> Tokens, uint Value) : RValueExpressionNode(Tokens, new NubIntType(false, 32))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record U64LiteralNode(List<Token> Tokens, ulong Value) : RValueExpressionNode(Tokens, new NubIntType(false, 64));
public record U64LiteralNode(List<Token> Tokens, ulong Value) : RValueExpressionNode(Tokens, new NubIntType(false, 64))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record Float32LiteralNode(List<Token> Tokens, float Value) : RValueExpressionNode(Tokens, new NubFloatType(32));
public record Float32LiteralNode(List<Token> Tokens, float Value) : RValueExpressionNode(Tokens, new NubFloatType(32))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record Float64LiteralNode(List<Token> Tokens, double Value) : RValueExpressionNode(Tokens, new NubFloatType(64));
public record Float64LiteralNode(List<Token> Tokens, double Value) : RValueExpressionNode(Tokens, new NubFloatType(64))
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record BoolLiteralNode(List<Token> Tokens, NubType Type, bool Value) : RValueExpressionNode(Tokens, Type);
public record BoolLiteralNode(List<Token> Tokens, NubType Type, bool Value) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record BinaryExpressionNode(List<Token> Tokens, NubType Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right) : RValueExpressionNode(Tokens, Type);
public record BinaryExpressionNode(List<Token> Tokens, NubType Type, ExpressionNode Left, BinaryOperator Operator, ExpressionNode Right) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Left;
yield return Right;
}
}
public record UnaryExpressionNode(List<Token> Tokens, NubType Type, UnaryOperator Operator, ExpressionNode Operand) : RValueExpressionNode(Tokens, Type);
public record UnaryExpressionNode(List<Token> Tokens, NubType Type, UnaryOperator Operator, ExpressionNode Operand) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Operand;
}
}
public record FuncCallNode(List<Token> Tokens, NubType Type, ExpressionNode Expression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type);
public record FuncCallNode(List<Token> Tokens, NubType Type, ExpressionNode Expression, List<ExpressionNode> Parameters) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Expression;
foreach (var expressionNode in Parameters)
{
yield return expressionNode;
}
}
}
public record VariableIdentifierNode(List<Token> Tokens, NubType Type, string Name) : LValueExpressionNode(Tokens, Type);
public record VariableIdentifierNode(List<Token> Tokens, NubType Type, string Name) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record FuncIdentifierNode(List<Token> Tokens, NubType Type, string Module, string Name, string? ExternSymbol) : RValueExpressionNode(Tokens, Type);
public record FuncIdentifierNode(List<Token> Tokens, NubType Type, string Module, string Name, string? ExternSymbol) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type);
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return Values;
}
}
public record ConstArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type);
public record ConstArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return Values;
}
}
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Index;
}
}
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Index;
}
}
public record SliceIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record SliceIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Target;
yield return Index;
}
}
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type);
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return LValue;
}
}
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type);
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Target;
}
}
public record StructInitializerNode(List<Token> Tokens, NubType Type, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(Tokens, Type);
public record StructInitializerNode(List<Token> Tokens, NubType Type, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
foreach (var initializer in Initializers)
{
yield return initializer.Value;
}
}
}
public record DereferenceNode(List<Token> Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type);
public record DereferenceNode(List<Token> Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Target;
}
}
public record ConvertIntNode(List<Token> Tokens, ExpressionNode Value, int StartWidth, int TargetWidth, bool StartSignedness, bool TargetSignedness) : RValueExpressionNode(Tokens, new NubIntType(TargetSignedness, TargetWidth));
public record SizeNode(List<Token> Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
public record ConvertFloatNode(List<Token> Tokens, ExpressionNode Value, int StartWidth, int TargetWidth) : RValueExpressionNode(Tokens, new NubFloatType(TargetWidth));
public record CastNode(List<Token> Tokens, NubType Type, ExpressionNode Value) : RValueExpressionNode(Tokens, Type)
{
public override IEnumerable<Node> Children()
{
yield return Value;
}
}
public record ConvertCStringToStringNode(List<Token> Tokens, ExpressionNode Value) : RValueExpressionNode(Tokens, new NubStringType());
public record SizeBuiltinNode(List<Token> Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type);
public record FloatToIntBuiltinNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
public record ConstArrayToSliceNode(List<Token> Tokens, NubType Type, ExpressionNode Array) : RValueExpressionNode(Tokens, Type);
public record EnumReferenceIntermediateNode(List<Token> Tokens, string Module, string Name) : IntermediateExpression(Tokens);
public record EnumReferenceIntermediateNode(List<Token> Tokens, string Module, string Name) : IntermediateExpression(Tokens)
{
public override IEnumerable<Node> Children()
{
return [];
}
}
#endregion

View File

@@ -309,69 +309,97 @@ public sealed class TypeChecker
FloatLiteralSyntax expression => CheckFloatLiteral(expression, expectedType),
MemberAccessSyntax expression => CheckMemberAccess(expression, expectedType),
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
InterpretBuiltinSyntax expression => CheckExpression(expression.Target, expectedType) with { Type = ResolveType(expression.Type) },
SizeBuiltinSyntax expression => new SizeBuiltinNode(node.Tokens, new NubIntType(false, 64), ResolveType(expression.Type)),
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression, expectedType),
InterpretSyntax expression => CheckExpression(expression.Target, expectedType) with { Type = ResolveType(expression.Type) },
SizeSyntax expression => new SizeNode(node.Tokens, new NubIntType(false, 64), ResolveType(expression.Type)),
CastSyntax expression => CheckCast(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
switch (expectedType)
if (expectedType != null)
{
// note(nub31): Implicit conversion of const array to unsized array
case NubArrayType when result.Type is NubConstArrayType constArrayType:
{
return result with { Type = new NubArrayType(constArrayType.ElementType) };
}
// note(nub31): Implicit conversion of const array to slice
case NubSliceType when result.Type is NubConstArrayType constArrayType:
{
return new ConstArrayToSliceNode(result.Tokens, new NubSliceType(constArrayType.ElementType), result);
}
// note(nub31): Implicit conversion of int to larger int
case NubIntType expectedIntType when result.Type is NubIntType intType && expectedIntType.Width > intType.Width:
{
return new ConvertIntNode(result.Tokens, result, intType.Width, expectedIntType.Width, intType.Signed, expectedIntType.Signed);
}
// note(nub31): Implicit conversion of f32 to f64
case NubFloatType expectedFloatType when result.Type is NubFloatType floatType && expectedFloatType.Width > floatType.Width:
{
return new ConvertFloatNode(result.Tokens, result, floatType.Width, expectedFloatType.Width);
}
// note(nub31): Implicit conversion of cstring to string
case NubStringType when result.Type is NubCStringType:
{
return new ConvertCStringToStringNode(result.Tokens, result);
}
// note(nub31): No implicit conversion was possible or the result value was already the correct type
default:
if (result.Type == expectedType)
{
return result;
}
if (IsCastAllowed(result.Type, expectedType))
{
return new CastNode(result.Tokens, expectedType, result);
}
}
return result;
}
// todo(nub31): Infer int type instead of explicit type syntax
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression, NubType? _)
private ExpressionNode CheckCast(CastSyntax expression, NubType? expectedType)
{
var value = CheckExpression(expression.Value);
if (value.Type is not NubFloatType sourceFloatType)
if (expectedType == null)
{
throw new TypeCheckerException(Diagnostic
.Error("Source type of float to int conversion must be an float")
.At(expression.Value)
.Error("Unable to infer target type of cast")
.At(expression)
.WithHelp("Specify target type where value is used")
.Build());
}
var targetType = ResolveType(expression.Type);
if (targetType is not NubIntType targetIntType)
var value = CheckExpression(expression.Value, expectedType);
if (value.Type == expectedType)
{
Diagnostics.Add(Diagnostic
.Warning("Target type of cast is same as the value. Cast is unnecessary")
.At(expression)
.Build());
return value;
}
if (!IsCastAllowed(value.Type, expectedType, false))
{
throw new TypeCheckerException(Diagnostic
.Error("Target type of float to int conversion must be an integer")
.At(expression.Type)
.Error($"Cannot cast from {value.Type} to {expectedType}")
.Build());
}
return new FloatToIntBuiltinNode(expression.Tokens, targetIntType, value, sourceFloatType, targetIntType);
return new CastNode(expression.Tokens, expectedType, value);
}
private static bool IsCastAllowed(NubType from, NubType to, bool strict = true)
{
// note(nub31): Implicit casts
switch (from)
{
case NubIntType fromInt when to is NubIntType toInt && fromInt.Width < toInt.Width:
case NubPointerType when to is NubPointerType { BaseType: NubVoidType }:
case NubConstArrayType constArrayType1 when to is NubArrayType arrayType && constArrayType1.ElementType == arrayType.ElementType:
case NubConstArrayType constArrayType3 when to is NubSliceType sliceType2 && constArrayType3.ElementType == sliceType2.ElementType:
case NubCStringType when to is NubStringType:
{
return true;
}
}
if (!strict)
{
// note(nub31): Explicit casts
switch (from)
{
case NubIntType when to is NubIntType:
case NubIntType when to is NubFloatType:
case NubFloatType when to is NubIntType:
case NubFloatType when to is NubFloatType:
case NubPointerType when to is NubPointerType:
case NubPointerType when to is NubIntType:
case NubIntType when to is NubPointerType:
case NubCStringType when to is NubPointerType { BaseType: NubIntType { Width: 8 } }:
{
return true;
}
}
}
return false;
}
private AddressOfNode CheckAddressOf(AddressOfSyntax expression, NubType? expectedType)
@@ -499,6 +527,13 @@ public sealed class TypeChecker
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
}
@@ -517,6 +552,13 @@ public sealed class TypeChecker
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
}
@@ -533,21 +575,36 @@ public sealed class TypeChecker
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, new NubBoolType(), left, op, right);
}
case BinaryOperatorSyntax.Plus:
{
var left = CheckExpression(expression.Left, expectedType);
if (left.Type is not NubIntType and not NubFloatType and not NubStringType and not NubCStringType)
if (left.Type is not NubIntType and not NubFloatType)
{
throw new TypeCheckerException(Diagnostic
.Error("The plus operator must be used with int, float, cstring or string types")
.Error("The plus operator must only be used with int and float types")
.At(expression.Left)
.Build());
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
}
case BinaryOperatorSyntax.Minus:
@@ -565,6 +622,13 @@ public sealed class TypeChecker
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
}
@@ -584,6 +648,13 @@ public sealed class TypeChecker
}
var right = CheckExpression(expression.Right, left.Type);
if (right.Type != left.Type)
{
throw new TypeCheckerException(Diagnostic
.Error($"Expected type {left.Type} from left side of binary expression, but got {right.Type}")
.At(expression.Right)
.Build());
}
return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
}

View File

@@ -339,19 +339,15 @@ public class Generator
BoolLiteralNode boolLiteralNode => boolLiteralNode.Value ? "true" : "false",
ConstArrayIndexAccessNode constArrayIndexAccessNode => EmitConstArrayIndexAccess(constArrayIndexAccessNode),
ConstArrayInitializerNode constArrayInitializerNode => EmitConstArrayInitializer(constArrayInitializerNode),
ConstArrayToSliceNode constArrayToSliceNode => EmitConstArrayToSlice(constArrayToSliceNode),
ConvertCStringToStringNode convertCStringToStringNode => EmitConvertCStringToString(convertCStringToStringNode),
ConvertFloatNode convertFloatNode => EmitConvertFloat(convertFloatNode),
ConvertIntNode convertIntNode => EmitConvertInt(convertIntNode),
CStringLiteralNode cStringLiteralNode => $"\"{cStringLiteralNode.Value}\"",
DereferenceNode dereferenceNode => EmitDereference(dereferenceNode),
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(float32LiteralNode),
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(float64LiteralNode),
FloatToIntBuiltinNode floatToIntBuiltinNode => EmitFloatToIntBuiltin(floatToIntBuiltinNode),
CastNode castNode => EmitCast(castNode),
FuncCallNode funcCallNode => EmitFuncCall(funcCallNode),
FuncIdentifierNode funcIdentifierNode => FuncName(funcIdentifierNode.Module, funcIdentifierNode.Name, funcIdentifierNode.ExternSymbol),
AddressOfNode addressOfNode => EmitAddressOf(addressOfNode),
SizeBuiltinNode sizeBuiltinNode => $"sizeof({CType.Create(sizeBuiltinNode.TargetType)})",
SizeNode sizeBuiltinNode => $"sizeof({CType.Create(sizeBuiltinNode.TargetType)})",
SliceIndexAccessNode sliceIndexAccessNode => EmitSliceArrayIndexAccess(sliceIndexAccessNode),
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
@@ -442,46 +438,6 @@ public class Generator
return $"({CType.Create(arrayType.ElementType)}[{arrayType.Size}]){{{string.Join(", ", values)}}}";
}
private string EmitConstArrayToSlice(ConstArrayToSliceNode constArrayToSliceNode)
{
var arrayType = (NubConstArrayType)constArrayToSliceNode.Array.Type;
var array = EmitExpression(constArrayToSliceNode.Array);
return $"(slice){{.length = {arrayType.Size}, .data = (void*){array}}}";
}
private string EmitConvertCStringToString(ConvertCStringToStringNode convertCStringToStringNode)
{
var value = EmitExpression(convertCStringToStringNode.Value);
return $"(string){{.length = strlen({value}), .data = {value}}}";
}
private string EmitConvertFloat(ConvertFloatNode convertFloatNode)
{
var value = EmitExpression(convertFloatNode.Value);
var targetCast = convertFloatNode.TargetWidth switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetCast}){value}";
}
private string EmitConvertInt(ConvertIntNode convertIntNode)
{
var value = EmitExpression(convertIntNode.Value);
var targetType = convertIntNode.TargetWidth switch
{
8 => convertIntNode.TargetSignedness ? "int8_t" : "uint8_t",
16 => convertIntNode.TargetSignedness ? "int16_t" : "uint16_t",
32 => convertIntNode.TargetSignedness ? "int32_t" : "uint32_t",
64 => convertIntNode.TargetSignedness ? "int64_t" : "uint64_t",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetType}){value}";
}
private string EmitDereference(DereferenceNode dereferenceNode)
{
var pointer = EmitExpression(dereferenceNode.Target);
@@ -510,18 +466,22 @@ public class Generator
return str;
}
private string EmitFloatToIntBuiltin(FloatToIntBuiltinNode floatToIntBuiltinNode)
private string EmitCast(CastNode castNode)
{
var value = EmitExpression(floatToIntBuiltinNode.Value);
var targetType = floatToIntBuiltinNode.TargetType.Width switch
var value = EmitExpression(castNode.Value);
if (castNode is { Type: NubSliceType, Value.Type: NubConstArrayType arrayType })
{
8 => floatToIntBuiltinNode.TargetType.Signed ? "int8_t" : "uint8_t",
16 => floatToIntBuiltinNode.TargetType.Signed ? "int16_t" : "uint16_t",
32 => floatToIntBuiltinNode.TargetType.Signed ? "int32_t" : "uint32_t",
64 => floatToIntBuiltinNode.TargetType.Signed ? "int64_t" : "uint64_t",
_ => throw new ArgumentOutOfRangeException()
};
return $"({targetType}){value}";
return $"(slice){{.length = {arrayType.Size}, .data = (void*){value}}}";
}
// todo(nub31): Stop depending on libc
if (castNode is { Type: NubCStringType, Value.Type: NubStringType })
{
return $"(string){{.length = strlen({value}), .data = {value}}}";
}
return $"({CType.Create(castNode.Type)}){value}";
}
private string EmitFuncCall(FuncCallNode funcCallNode)

View File

@@ -508,7 +508,7 @@ public sealed class Parser
{
var type = ParseType();
ExpectSymbol(Symbol.CloseParen);
return new SizeBuiltinSyntax(GetTokens(startIndex), type);
return new SizeSyntax(GetTokens(startIndex), type);
}
case "interpret":
{
@@ -516,15 +516,13 @@ public sealed class Parser
ExpectSymbol(Symbol.Comma);
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return new InterpretBuiltinSyntax(GetTokens(startIndex), type, expression);
return new InterpretSyntax(GetTokens(startIndex), type, expression);
}
case "floatToInt":
case "cast":
{
var type = ParseType();
ExpectSymbol(Symbol.Comma);
var expression = ParseExpression();
ExpectSymbol(Symbol.CloseParen);
return new FloatToIntBuiltinSyntax(GetTokens(startIndex), type, expression);
return new CastSyntax(GetTokens(startIndex), expression);
}
default:
{

View File

@@ -112,11 +112,11 @@ public record StructInitializerSyntax(List<Token> Tokens, TypeSyntax? StructType
public record DereferenceSyntax(List<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record SizeBuiltinSyntax(List<Token> Tokens, TypeSyntax Type) : ExpressionSyntax(Tokens);
public record SizeSyntax(List<Token> Tokens, TypeSyntax Type) : ExpressionSyntax(Tokens);
public record InterpretBuiltinSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record InterpretSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
public record FloatToIntBuiltinSyntax(List<Token> Tokens, TypeSyntax Type, ExpressionSyntax Value) : ExpressionSyntax(Tokens);
public record CastSyntax(List<Token> Tokens, ExpressionSyntax Value) : ExpressionSyntax(Tokens);
#endregion

View File

@@ -37,8 +37,8 @@ extern "main" func main(argc: i64, argv: [?]cstring): i64
direction.y = -1
}
x = x + @floatToInt(i32, direction.x * speed * raylib::GetFrameTime())
y = y + @floatToInt(i32, direction.y * speed * raylib::GetFrameTime())
x = x + @cast(direction.x * speed * raylib::GetFrameTime())
y = y + @cast(direction.y * speed * raylib::GetFrameTime())
raylib::BeginDrawing()
{

View File

@@ -1,2 +1,3 @@
node_modules
out
out
nub-*.vsix

View File

@@ -1,5 +0,0 @@
import { defineConfig } from '@vscode/test-cli';
export default defineConfig({
files: 'out/test/**/*.test.js',
});

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>generated c soruce</title>
</head>
<body>
<pre id="assembly">{{assembly}}</pre>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "nub",
"displayName": "Nub Language Support",
"description": "Language server client for nub lang",
"version": "0.0.0",
"version": "0.0.1",
"publisher": "nub31",
"repository": {
"type": "git",
@@ -15,6 +15,12 @@
"Programming Languages"
],
"main": "./out/extension.js",
"files": [
"out",
"server",
"syntaxes",
"language-configuration.json"
],
"contributes": {
"languages": [
{
@@ -31,31 +37,17 @@
"scopeName": "source.nub",
"path": "./syntaxes/nub.tmLanguage.json"
}
],
"commands": [
{
"command": "nub.openOutput",
"title": "Nub: Show Output",
"icon": "$(open-preview)"
}
],
"menus": {
"editor/title": [
{
"command": "nub.openOutput",
"when": "editorLangId == nub || resourceExtname == .nub",
"group": "navigation"
}
]
}
]
},
"scripts": {
"build": "tsc -p ./",
"watch": "tsc -watch -p ./"
"build": "esbuild src/extension.ts --bundle --platform=node --outfile=out/extension.js --external:vscode",
"package": "vsce package"
},
"devDependencies": {
"@types/node": "22.x",
"@types/vscode": "^1.105.0",
"@vscode/vsce": "^3.6.2",
"esbuild": "^0.25.11",
"typescript": "^5.9.3"
},
"dependencies": {

View File

@@ -4,7 +4,7 @@ import { LanguageClient, TransportKind } from 'vscode-languageclient/node';
let client: LanguageClient;
export function activate(context: vscode.ExtensionContext) {
export async function activate(context: vscode.ExtensionContext) {
const serverExecutable = path.join(context.asAbsolutePath('server'), "nublsp");
client = new LanguageClient(
@@ -32,14 +32,6 @@ export function activate(context: vscode.ExtensionContext) {
}
);
client.onNotification("nub/output", (params: { path: string, content: string }) => {
});
vscode.commands.registerCommand('nub.openOutput', async () => {
});
client.start();
}