This commit is contained in:
nub31
2025-05-28 14:15:16 +02:00
parent 3d095ec648
commit a098065136
7 changed files with 93 additions and 53 deletions

View File

@@ -1,24 +1,30 @@
namespace main namespace main
struct Human {
}
/// # Documentation /// # Documentation
/// ## Documentation subtitle /// ## Documentation subtitle
export func main(args: []string) { export func main(args: []^string) {
let i: i64 let i: i64
c::printf("%d\n", args.count) c::printf("%d\n", args.count)
while i < args.count { while i < args.count {
c::printf("%s\n", args[i]) 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 i = 0
while i < arr.count { while i < arr.count + 1 {
c::printf("%d\n", arr[i]) c::printf("%d\n", arr[i])
i += 1
i === 1
} }
c::printf("success\n", "")
} }

View File

@@ -7,6 +7,8 @@ namespace Nub.Lang.Backend;
public class Generator public class Generator
{ {
private const string OutOfBoundsMessage = "Index is out of bounds\n";
private List<SourceFile> _sourceFiles = []; private List<SourceFile> _sourceFiles = [];
private StringBuilder _builder = new(); private StringBuilder _builder = new();
private Dictionary<string, Variable> _variables = []; private Dictionary<string, Variable> _variables = [];
@@ -68,12 +70,14 @@ public class Generator
_builder.AppendLine(); _builder.AppendLine();
} }
_builder.AppendLine($"data $oob_message = {{ b \"{OutOfBoundsMessage}\" }}");
for (var i = 0; i < _strings.Count; i++) for (var i = 0; i < _strings.Count; i++)
{ {
var str = _strings[i]; var str = _strings[i];
_builder.AppendLine($"data $str{i + 1} = {{ b \"{str}\", b 0 }}"); _builder.AppendLine($"data $str{i + 1} = {{ b \"{str}\", b 0 }}");
} }
return _builder.ToString(); return _builder.ToString();
} }
@@ -578,15 +582,39 @@ public class Generator
var index = GenerateExpression(arrayIndex.Index); var index = GenerateExpression(arrayIndex.Index);
var arrayBaseType = ((NubArrayType)arrayIndex.Expression.Type).BaseType; 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(); var firstItemPointerName = GenVarName();
_builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8"); _builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8");
var offsetPointerName = GenVarName(); var offsetPointerName = GenVarName();
_builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}"); _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}");
var resultPointerName = GenVarName(); 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(); var outputName = GenVarName();
_builder.AppendLine($" %{outputName} =l load{SQT(arrayBaseType)} %{resultPointerName}"); _builder.AppendLine($" %{outputName} ={SQT(arrayBaseType)} load{SQT(arrayBaseType)} %{resultPointerName}");
return $"%{outputName}"; return $"%{outputName}";
} }

View File

@@ -15,7 +15,7 @@ public class Lexer
["break"] = Symbol.Break, ["break"] = Symbol.Break,
["continue"] = Symbol.Continue, ["continue"] = Symbol.Continue,
["return"] = Symbol.Return, ["return"] = Symbol.Return,
["new"] = Symbol.New, ["alloc"] = Symbol.Alloc,
["struct"] = Symbol.Struct, ["struct"] = Symbol.Struct,
["let"] = Symbol.Let, ["let"] = Symbol.Let,
}; };

View File

@@ -38,11 +38,11 @@ public enum Symbol
Minus, Minus,
Star, Star,
ForwardSlash, ForwardSlash,
New,
Struct, Struct,
Caret, Caret,
Ampersand, Ampersand,
DoubleColon, DoubleColon,
Namespace, Namespace,
Let Let,
Alloc
} }

View File

@@ -507,43 +507,6 @@ public class Parser
expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast); expr = new CastNode(GetTokensForNode(startIndex), type, expressionToCast);
break; 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<string, ExpressionNode> 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: case Symbol.Ampersand:
{ {
var expression = ParsePrimaryExpression(); var expression = ParsePrimaryExpression();
@@ -562,6 +525,38 @@ public class Parser
expr = new UnaryExpressionNode(GetTokensForNode(startIndex), UnaryExpressionOperator.Invert, expression); expr = new UnaryExpressionNode(GetTokensForNode(startIndex), UnaryExpressionOperator.Invert, expression);
break; 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<string, ExpressionNode> 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: default:
{ {
throw new ParseException(Diagnostic throw new ParseException(Diagnostic

View File

@@ -28,6 +28,17 @@ nub_strcmp:
mov rax, 1 mov rax, 1
ret 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 ; TODO: This is ai-generated. Should be re-implemented in the future
global nub_memset global nub_memset
nub_memset: nub_memset:

View File

@@ -60,7 +60,7 @@
}, },
{ {
"name": "keyword.other.nub", "name": "keyword.other.nub",
"match": "\\b(namespace|func|struct|new)\\b" "match": "\\b(namespace|func|struct|alloc)\\b"
} }
] ]
}, },
@@ -256,4 +256,4 @@
] ]
} }
} }
} }