diff --git a/Nub.Lang/Nub.Lang/Generation/Generator.cs b/Nub.Lang/Nub.Lang/Generation/Generator.cs index 4fc2fab..e0887d5 100644 --- a/Nub.Lang/Nub.Lang/Generation/Generator.cs +++ b/Nub.Lang/Nub.Lang/Generation/Generator.cs @@ -66,6 +66,26 @@ public class Generator _builder.AppendLine(); GenerateFuncDefinition(funcDefinition); } + + _builder.AppendLine(""" + + ; https://tuttlem.github.io/2013/01/08/strlen-implementation-in-nasm.html + strlen: + push rcx ; save and clear out counter + xor rcx, rcx + .strlen_next: + cmp [rdi], byte 0 ; null byte yet? + jz .strlen_null ; yes, get out + inc rcx ; char is ok, count it + inc rdi ; move to next char + jmp .strlen_next ; process again + .strlen_null: + mov rax, rcx ; rcx = the length (put in rax) + pop rcx ; restore rcx + ret ; get out + """); + + _builder.AppendLine(); _builder.AppendLine("section .data"); foreach (var str in _strings) @@ -148,6 +168,9 @@ public class Generator case LiteralNode literal: GenerateLiteral(literal, func); break; + case StrlenNode strlen: + GenerateStrlen(strlen, func); + break; case SyscallExpressionNode syscallExpression: throw new NotImplementedException(); break; @@ -232,6 +255,13 @@ public class Generator } } + private void GenerateStrlen(StrlenNode strlen, Func func) + { + GenerateExpression(strlen.String, func); + _builder.AppendLine(" mov rdi, rax"); + _builder.AppendLine(" call strlen"); + } + // TODO: Use stack for more than 6 parameters private void GenerateFuncCall(FuncCall funcCall, Func func) { diff --git a/Nub.Lang/Nub.Lang/Input/program.nub b/Nub.Lang/Nub.Lang/Input/program.nub index ab313f4..aa0891e 100644 --- a/Nub.Lang/Nub.Lang/Input/program.nub +++ b/Nub.Lang/Nub.Lang/Input/program.nub @@ -7,6 +7,6 @@ func main() { write("test\n"); } -func write(msg: pointer) { - syscall(SYS_WRITE, STD_OUT, msg, 5); +func write(msg: String) { + syscall(SYS_WRITE, STD_OUT, msg, strlen(msg)); } \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Parsing/Parser.cs b/Nub.Lang/Nub.Lang/Parsing/Parser.cs index 88e1197..fa16e61 100644 --- a/Nub.Lang/Nub.Lang/Parsing/Parser.cs +++ b/Nub.Lang/Nub.Lang/Parsing/Parser.cs @@ -144,7 +144,12 @@ public class Parser { return new SyscallExpressionNode(new Syscall(parameters)); } - + + if (identifier.Value == "strlen" && parameters.Count == 1) + { + return new StrlenNode(parameters[0]); + } + return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters)); } @@ -184,7 +189,7 @@ public class Parser return new DelegateType(typeArguments.Take(typeArguments.Count - 1).ToList(), returnType); } - if (name == "pointer") + if (name == "String") { return new StringType(); } diff --git a/Nub.Lang/Nub.Lang/Parsing/StrlenNode.cs b/Nub.Lang/Nub.Lang/Parsing/StrlenNode.cs new file mode 100644 index 0000000..70244e2 --- /dev/null +++ b/Nub.Lang/Nub.Lang/Parsing/StrlenNode.cs @@ -0,0 +1,6 @@ +namespace Nub.Lang.Parsing; + +public class StrlenNode(ExpressionNode @string) : ExpressionNode +{ + public ExpressionNode String { get; } = @string; +} \ No newline at end of file diff --git a/Nub.Lang/Nub.Lang/Type.cs b/Nub.Lang/Nub.Lang/Type.cs index ef42cdb..b094b06 100644 --- a/Nub.Lang/Nub.Lang/Type.cs +++ b/Nub.Lang/Nub.Lang/Type.cs @@ -56,7 +56,7 @@ public enum PrimitiveTypeKind public record StringType : Type { - public override string ToString() => "string"; + public override string ToString() => "String"; } public record DelegateType : Type diff --git a/Nub.Lang/Nub.Lang/Typing/ExpressionTyper.cs b/Nub.Lang/Nub.Lang/Typing/ExpressionTyper.cs index 737c6ea..1c5cdc2 100644 --- a/Nub.Lang/Nub.Lang/Typing/ExpressionTyper.cs +++ b/Nub.Lang/Nub.Lang/Typing/ExpressionTyper.cs @@ -104,6 +104,9 @@ public class ExpressionTyper case LiteralNode literal: PopulateLiteral(literal); break; + case StrlenNode strlen: + PopulateStrlen(strlen); + break; case SyscallExpressionNode syscall: PopulateSyscallExpression(syscall); break; @@ -146,6 +149,11 @@ public class ExpressionTyper literal.Type = literal.LiteralType; } + private static void PopulateStrlen(StrlenNode strlen) + { + strlen.Type = new PrimitiveType(PrimitiveTypeKind.Int64); + } + private void PopulateSyscallExpression(SyscallExpressionNode syscall) { foreach (var parameter in syscall.Syscall.Parameters)