From bba7906221f4c5588d3001fab2604ace29914a73 Mon Sep 17 00:00:00 2001 From: nub31 Date: Wed, 28 May 2025 14:15:16 +0200 Subject: [PATCH] ... --- example/program.nub | 20 ++++-- src/lang/Nub.Lang/Backend/Generator.cs | 36 ++++++++-- src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs | 2 +- .../Nub.Lang/Frontend/Lexing/SymbolToken.cs | 4 +- src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 69 +++++++++---------- src/runtime/runtime.asm | 11 +++ .../syntaxes/nub.tmLanguage.json | 4 +- 7 files changed, 93 insertions(+), 53 deletions(-) diff --git a/example/program.nub b/example/program.nub index be5459c..2da8f81 100644 --- a/example/program.nub +++ b/example/program.nub @@ -1,24 +1,30 @@ namespace main +struct Human { + +} + /// # Documentation /// ## Documentation subtitle -export func main(args: []string) { +export func main(args: []^string) { let i: i64 c::printf("%d\n", args.count) while i < args.count { c::printf("%s\n", args[i]) - - i === 1 + i += 1 } - let arr = new [10]i64 + let human = alloc Human {} + + let arr = [10]^i64 i = 0 - while i < arr.count { + while i < arr.count + 1 { c::printf("%d\n", arr[i]) - - i === 1 + i += 1 } + + c::printf("success\n", "") } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Backend/Generator.cs b/src/lang/Nub.Lang/Backend/Generator.cs index bbdca5d..73e5b6c 100644 --- a/src/lang/Nub.Lang/Backend/Generator.cs +++ b/src/lang/Nub.Lang/Backend/Generator.cs @@ -7,6 +7,8 @@ namespace Nub.Lang.Backend; public class Generator { + private const string OutOfBoundsMessage = "Index is out of bounds\n"; + private List _sourceFiles = []; private StringBuilder _builder = new(); private Dictionary _variables = []; @@ -68,12 +70,14 @@ public class Generator _builder.AppendLine(); } + _builder.AppendLine($"data $oob_message = {{ b \"{OutOfBoundsMessage}\" }}"); + for (var i = 0; i < _strings.Count; i++) { var str = _strings[i]; _builder.AppendLine($"data $str{i + 1} = {{ b \"{str}\", b 0 }}"); } - + return _builder.ToString(); } @@ -578,15 +582,39 @@ public class Generator var index = GenerateExpression(arrayIndex.Index); var arrayBaseType = ((NubArrayType)arrayIndex.Expression.Type).BaseType; - + + var countName = GenVarName(); + _builder.AppendLine($" %{countName} =l loadl {array}"); + + var isNegativeName = GenVarName(); + _builder.AppendLine($" %{isNegativeName} =w csltl {index}, 0"); + + var isOobName = GenVarName(); + _builder.AppendLine($" %{isOobName} =w csgel {index}, %{countName}"); + + var anyOobName = GenVarName(); + _builder.AppendLine($" %{anyOobName} =w or %{isNegativeName}, %{isOobName}"); + + var oobLabel = GenLabelName(); + var notOobLabel = GenLabelName(); + _builder.AppendLine($" jnz %{anyOobName}, @{oobLabel}, @{notOobLabel}"); + + _builder.AppendLine($"@{oobLabel}"); + _builder.AppendLine($" call $nub_panic(l $oob_message, l {OutOfBoundsMessage.Length})"); + + _builder.AppendLine($"@{notOobLabel}"); + + // Calculate element address var firstItemPointerName = GenVarName(); _builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8"); var offsetPointerName = GenVarName(); _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}"); var resultPointerName = GenVarName(); - _builder.AppendLine($" %{resultPointerName} ={SQT(arrayIndex.Type)} add %{firstItemPointerName}, %{offsetPointerName}"); + _builder.AppendLine($" %{resultPointerName} =l add %{firstItemPointerName}, %{offsetPointerName}"); + + // Load the value var outputName = GenVarName(); - _builder.AppendLine($" %{outputName} =l load{SQT(arrayBaseType)} %{resultPointerName}"); + _builder.AppendLine($" %{outputName} ={SQT(arrayBaseType)} load{SQT(arrayBaseType)} %{resultPointerName}"); return $"%{outputName}"; } diff --git a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs index 40bdf03..f3187ab 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -15,7 +15,7 @@ public class Lexer ["break"] = Symbol.Break, ["continue"] = Symbol.Continue, ["return"] = Symbol.Return, - ["new"] = Symbol.New, + ["alloc"] = Symbol.Alloc, ["struct"] = Symbol.Struct, ["let"] = Symbol.Let, }; diff --git a/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs b/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs index dc82a9a..b01a0fe 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/SymbolToken.cs @@ -38,11 +38,11 @@ public enum Symbol Minus, Star, ForwardSlash, - New, Struct, Caret, Ampersand, DoubleColon, Namespace, - Let + Let, + Alloc } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index 5f2fb80..3ca3a96 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -507,43 +507,6 @@ public class Parser expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast); break; } - case Symbol.New: - { - var next = Peek(); - if (next.Value is SymbolToken { Symbol: Symbol.OpenBracket }) - { - Next(); - var size = ParseExpression(); - ExpectSymbol(Symbol.CloseBracket); - var type = ParseType(); - expr = new ArrayInitializerNode(GetTokensForNode(startIndex), size, type); - } - else - { - var type = ParseType(); - Dictionary initializers = []; - ExpectSymbol(Symbol.OpenBrace); - while (!TryExpectSymbol(Symbol.CloseBrace)) - { - var name = ExpectIdentifier().Value; - ExpectSymbol(Symbol.Assign); - var value = ParseExpression(); - initializers.Add(name, value); - } - - if (type is not NubStructType structType) - { - throw new ParseException(Diagnostic - .Error($"Cannot use new keyword on type {type}") - .At(symbolToken) - .Build()); - } - - expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); - } - - break; - } case Symbol.Ampersand: { var expression = ParsePrimaryExpression(); @@ -562,6 +525,38 @@ public class Parser expr = new UnaryExpressionNode(GetTokensForNode(startIndex), UnaryExpressionOperator.Invert, expression); break; } + case Symbol.OpenBracket: + { + var size = ParseExpression(); + ExpectSymbol(Symbol.CloseBracket); + var type = ParseType(); + expr = new ArrayInitializerNode(GetTokensForNode(startIndex), size, type); + break; + } + case Symbol.Alloc: + { + var type = ParseType(); + Dictionary initializers = []; + ExpectSymbol(Symbol.OpenBrace); + while (!TryExpectSymbol(Symbol.CloseBrace)) + { + var name = ExpectIdentifier().Value; + ExpectSymbol(Symbol.Assign); + var value = ParseExpression(); + initializers.Add(name, value); + } + + if (type is not NubStructType structType) + { + throw new ParseException(Diagnostic + .Error($"Cannot use new keyword on type {type}") + .At(symbolToken) + .Build()); + } + + expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); + break; + } default: { throw new ParseException(Diagnostic diff --git a/src/runtime/runtime.asm b/src/runtime/runtime.asm index 77261c6..1562905 100644 --- a/src/runtime/runtime.asm +++ b/src/runtime/runtime.asm @@ -28,6 +28,17 @@ nub_strcmp: mov rax, 1 ret +global nub_panic +nub_panic: + mov rdx, rsi + mov rsi, rdi + mov rax, 1 + mov rdi, 2 + syscall + mov rax, 60 + mov rdi, 101 + syscall + ; TODO: This is ai-generated. Should be re-implemented in the future global nub_memset nub_memset: diff --git a/tools/syntax-highlighting/syntaxes/nub.tmLanguage.json b/tools/syntax-highlighting/syntaxes/nub.tmLanguage.json index 09752e2..ff66384 100644 --- a/tools/syntax-highlighting/syntaxes/nub.tmLanguage.json +++ b/tools/syntax-highlighting/syntaxes/nub.tmLanguage.json @@ -60,7 +60,7 @@ }, { "name": "keyword.other.nub", - "match": "\\b(namespace|func|struct|new)\\b" + "match": "\\b(namespace|func|struct|alloc)\\b" } ] }, @@ -256,4 +256,4 @@ ] } } -} \ No newline at end of file +}