From 75b9b53fdda4cc96af6bac7017c0d1a58982a5c0 Mon Sep 17 00:00:00 2001 From: sfja Date: Sun, 22 Dec 2024 02:30:23 +0100 Subject: [PATCH] add char literals --- compiler/arch.ts | 3 ++- compiler/lexer.ts | 26 +++++++++++++++++++ editors/vim/syntax/slige.vim | 3 +++ editors/vscode/syntaxes/slige.tmLanguage.json | 11 ++++++++ runtime/arch.hpp | 3 ++- runtime/vm.cpp | 8 +++++- tests/char_literal.slg | 10 +++++++ 7 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/char_literal.slg diff --git a/compiler/arch.ts b/compiler/arch.ts index eca36bd..b6fc64f 100644 --- a/compiler/arch.ts +++ b/compiler/arch.ts @@ -40,7 +40,8 @@ export const Ops = { export type Builtins = typeof Builtins; export const Builtins = { - IntToString: 0x00, + Exit: 0x00, + IntToString: 0x01, StringConcat: 0x10, StringEqual: 0x11, StringCharAt: 0x12, diff --git a/compiler/lexer.ts b/compiler/lexer.ts index 99c8e24..4774ae9 100644 --- a/compiler/lexer.ts +++ b/compiler/lexer.ts @@ -70,6 +70,32 @@ export class Lexer { return { ...this.token("int", pos), intValue: 0 }; } + if (this.test("'")) { + this.step(); + let value: string; + if (this.test("\\")) { + this.step(); + if (this.done()) { + this.report("malformed character literal", pos); + return this.token("error", pos); + } + value = { + n: "\n", + t: "\t", + "0": "\0", + }[this.current()] ?? this.current(); + } else { + value = this.current(); + } + this.step(); + if (this.done() || !this.test("'") || value.length === 0) { + this.report("malformed character literal", pos); + return this.token("error", pos); + } + this.step(); + return { ...this.token("int", pos), intValue: value.charCodeAt(0) }; + } + if (this.test('"')) { this.step(); let value = ""; diff --git a/editors/vim/syntax/slige.vim b/editors/vim/syntax/slige.vim index 89473ba..a9f334f 100644 --- a/editors/vim/syntax/slige.vim +++ b/editors/vim/syntax/slige.vim @@ -37,6 +37,9 @@ syn match Number '0[0-7]\+' syn match Number '0x[0-9a-fA-F]\+' syn match Number '0b[01]\+' +syn match Character "'[^\\]'" +syn match Character "'\\.'" + syn region String start=+"+ skip=+\\"+ end=+"+ syn keyword Todo contained TODO FIXME XXX NOTE diff --git a/editors/vscode/syntaxes/slige.tmLanguage.json b/editors/vscode/syntaxes/slige.tmLanguage.json index edbfb9d..99c0096 100644 --- a/editors/vscode/syntaxes/slige.tmLanguage.json +++ b/editors/vscode/syntaxes/slige.tmLanguage.json @@ -53,6 +53,17 @@ } ] }, + "chars": { + "name": "string.quoted.double.slige", + "begin": "'", + "end": "'", + "patterns": [ + { + "name": "constant.character.escape.slige", + "match": "\\\\." + } + ] + }, "numbers": { "patterns": [ { diff --git a/runtime/arch.hpp b/runtime/arch.hpp index d7ae557..91ce34d 100644 --- a/runtime/arch.hpp +++ b/runtime/arch.hpp @@ -41,7 +41,8 @@ enum class Op : uint32_t { }; enum class Builtin : uint32_t { - IntToString = 0x00, + Exit = 0x00, + IntToString = 0x01, StringConcat = 0x10, StringEqual = 0x11, StringCharAt = 0x12, diff --git a/runtime/vm.cpp b/runtime/vm.cpp index cd0087f..a659714 100644 --- a/runtime/vm.cpp +++ b/runtime/vm.cpp @@ -300,9 +300,15 @@ void VM::run_builtin(Builtin builtin_id) maybe_builtin_to_string(static_cast(builtin_id))); } switch (builtin_id) { + case Builtin::Exit: { + assert_stack_has(1); + auto status_code = stack_pop().as_int().value; + std::exit(status_code); + break; + } case Builtin::IntToString: { assert_stack_has(1); - auto number = static_cast(stack_pop().as_int().value); + auto number = stack_pop().as_int().value; auto str = std::to_string(number); stack_push(String(str)); break; diff --git a/tests/char_literal.slg b/tests/char_literal.slg new file mode 100644 index 0000000..91e1163 --- /dev/null +++ b/tests/char_literal.slg @@ -0,0 +1,10 @@ + +fn exit(status_code: int) #[builtin(Exit)] {} + +fn main() { + if 'A' != 65 { + exit(1); + } + exit(0); +} +