From b96fe32201e67df810a506bba53f8e314a2b9804 Mon Sep 17 00:00:00 2001 From: sfja Date: Mon, 16 Dec 2024 21:56:36 +0100 Subject: [PATCH] try add survery code coverage program 2 --- compiler/ast.ts | 2 +- compiler/checker.ts | 1 + compiler/compiler.ts | 2 +- compiler/info.ts | 2 +- compiler/lowerer.ts | 20 ++ compiler/parser.ts | 6 +- examples/survey_code_coverage_program_2.slg | 230 ++++++++++++++++++++ stdlib.slg | 22 +- 8 files changed, 273 insertions(+), 12 deletions(-) create mode 100644 examples/survey_code_coverage_program_2.slg diff --git a/compiler/ast.ts b/compiler/ast.ts index 2fdc401..4159b96 100644 --- a/compiler/ast.ts +++ b/compiler/ast.ts @@ -65,7 +65,7 @@ export type ExprKind = body: Expr; }; -export type UnaryType = "not"; +export type UnaryType = "not" | "-"; export type BinaryType = | "+" | "*" diff --git a/compiler/checker.ts b/compiler/checker.ts index 61181c4..f491b0d 100644 --- a/compiler/checker.ts +++ b/compiler/checker.ts @@ -629,6 +629,7 @@ const simpleUnaryOperations: { result?: VType; }[] = [ { unaryType: "not", operand: { type: "bool" } }, + { unaryType: "-", operand: { type: "int" } }, ]; const simpleBinaryOperations: { diff --git a/compiler/compiler.ts b/compiler/compiler.ts index 9309432..ec8666e 100644 --- a/compiler/compiler.ts +++ b/compiler/compiler.ts @@ -47,7 +47,7 @@ export class Compiler { const lowerer = new Lowerer(lexer.currentPos()); lowerer.lower(ast); - //lowerer.printProgram(); + lowerer.printProgram(); const { program, fnNames } = lowerer.finish(); return { program, fnNames }; diff --git a/compiler/info.ts b/compiler/info.ts index 55a3dad..f51f991 100644 --- a/compiler/info.ts +++ b/compiler/info.ts @@ -42,7 +42,7 @@ export function printStackTrace() { } } try { - throw new ReportNotAnError(); + //throw new ReportNotAnError(); } catch (error) { if (!(error instanceof ReportNotAnError)) { throw error; diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts index 973eac0..56b8ca3 100644 --- a/compiler/lowerer.ts +++ b/compiler/lowerer.ts @@ -349,6 +349,18 @@ export class Lowerer { default: } } + if (vtype.type === "int") { + switch (expr.kind.unaryType) { + case "-": { + this.program.add(Ops.PushInt, 0); + this.program.add(Ops.PushInt, 1); + this.program.add(Ops.Subtract); + this.program.add(Ops.Multiply); + return; + } + default: + } + } throw new Error( `unhandled unary` + ` '${vtypeToString(expr.vtype!)}' aka. ` + @@ -378,6 +390,10 @@ export class Lowerer { case "==": this.program.add(Ops.Equal); return; + case "!=": + this.program.add(Ops.Equal); + this.program.add(Ops.Not); + return; case "<": this.program.add(Ops.LessThan); return; @@ -408,6 +424,10 @@ export class Lowerer { this.program.add(Ops.Or); return; } + if (expr.kind.binaryType === "and") { + this.program.add(Ops.And); + return; + } } throw new Error( `unhandled binaryType` + diff --git a/compiler/parser.ts b/compiler/parser.ts index 75fee9b..04f7e46 100644 --- a/compiler/parser.ts +++ b/compiler/parser.ts @@ -10,6 +10,7 @@ import { Param, Stmt, StmtKind, + UnaryType, } from "./ast.ts"; import { printStackTrace, Reporter } from "./info.ts"; import { Lexer } from "./lexer.ts"; @@ -578,10 +579,11 @@ export class Parser { private parsePrefix(): Expr { const pos = this.pos(); - if (this.test("not")) { + if (this.test("not") || this.test("-")) { + const unaryType = this.current().type as UnaryType; this.step(); const subject = this.parsePrefix(); - return this.expr({ type: "unary", unaryType: "not", subject }, pos); + return this.expr({ type: "unary", unaryType, subject }, pos); } return this.parsePostfix(); } diff --git a/examples/survey_code_coverage_program_2.slg b/examples/survey_code_coverage_program_2.slg new file mode 100644 index 0000000..3f9e32f --- /dev/null +++ b/examples/survey_code_coverage_program_2.slg @@ -0,0 +1,230 @@ + +fn string_to_int_impl(text: string) -> int { + let base_2_digits = "01"; + let base_8_digits = base_2_digits + "234567"; + let base_10_digits = base_8_digits + "89"; + let base_16_digits = base_10_digits + "abcdef"; + + let len = string_length(text); + if len == 0 { + return 1; + } + println("hello world"); + + if text[0] == "0"[0] { + if len == 1 { + 0 + } else if text[1] == "b"[0] { + parse_digits(string_slice(text, 2, -1), 2, base_2_digits) + } else if text[1] == "x"[0] { + parse_digits(string_slice(text, 2, -1), 16, base_16_digits) + } else { + parse_digits(string_slice(text, 1, -1), 8, base_8_digits) + } + } else { + parse_digits(text, 10, base_10_digits) + } +} + +fn parse_digits(text: string, base: int, digit_set: string) -> int { + let val = 0; + let len = string_length(text); + for (let i = 0; i < len; i += 1) { + let ch = text[i]; + if not string_contains(digit_set, ch) { + return -1; + } + val = val * base; + val += char_val(ch); + } + val +} + +fn char_val(ch: int) -> int { + if ch >= "0"[0] and "9"[0] >= ch { + ch - "0"[0] + } else if ch >= "a"[0] and "f"[0] >= ch { + ch - "a"[0] + } else { + -1 + } +} + +fn test_string_to_int_impl() -> bool { + test("should convert zero", assert_int_equal(string_to_int_impl("0"), 0)) + or test("should convert decimal", assert_int_equal(string_to_int_impl("10"), 10)) + or test("should convert binary", assert_int_equal(string_to_int_impl("0b110"), 6)) + or test("should convert octal", assert_int_equal(string_to_int_impl("071"), 51)) + or test("should convert hexadecimal", assert_int_equal(string_to_int_impl("0xaa"), 170)) + or test("should fail", assert_int_equal(string_to_int_impl("john"), -1)) +} + +fn assert_int_equal(value: int, target: int) -> bool { + if value != target { + println("assertion failed: " + int_to_string(value) + " != " + int_to_string(target)); + return false; + } + true +} + +fn test(name: string, assertion: bool) -> bool { + println(" * test: " + name + " -> " + if assertion { "ok" } else { "failed" }); + assertion +} + +fn main() { + let ok = test_string_to_int_impl(); + if not ok { + println("tests failed!"); + } +} + +// + +fn print(msg: string) #[builtin(Print)] {} +fn println(msg: string) { print(msg + "\n") } + +fn int_to_string(number: int) -> string #[builtin(IntToString)] {} + +fn string_push_char(str: string, value: int) -> string #[builtin(StringPushChar)] {} +fn string_char_at(str: string, index: int) -> int #[builtin(StringCharAt)] {} +fn string_length(str: string) -> int #[builtin(StringLength)] {} +fn string_to_int(str: string) -> int #[builtin(StringToInt)] {} + +fn string_array_new() -> [string] #[builtin(ArrayNew)] {} +fn string_array_push(array: [string], value: string) #[builtin(ArrayPush)] {} +fn string_array_length(array: [string]) -> int #[builtin(ArrayLength)] {} +fn string_array_at(array: [string], index: int) -> string #[builtin(ArrayAt)] {} + +fn int_array_new() -> [int] #[builtin(ArrayNew)] {} +fn int_array_push(array: [int], value: int) #[builtin(ArrayPush)] {} +fn int_array_length(array: [int]) -> int #[builtin(ArrayLength)] {} +fn int_array_at(array: [int], index: int) -> int #[builtin(ArrayAt)] {} + +fn file_open(filename: string, mode: string) -> int #[builtin(FileOpen)] {} +fn file_close(file: int) #[builtin(FileClose)] {} +fn file_write_string(file: int, content: string) -> int #[builtin(FileWriteString)] {} +fn file_read_char(file: int) -> int #[builtin(FileReadChar)] {} +fn file_read_to_string(file: int) -> string #[builtin(FileReadToString)] {} +fn file_flush(file: int) #[builtin(FileFlush)] {} +fn file_eof(file: int) -> bool #[builtin(FileEof)] {} + + +fn stdin() -> int { 0 } +fn stdout() -> int { 1 } +fn stderr() -> int { 2 } + +fn file_read_line(file: int) -> string { + let line = ""; + loop { + if file_eof(file) { + break; + } + let ch = file_read_char(file); + if ch == "\n"[0] { + break; + } + line = string_push_char(line, ch); + } + line +} + +fn read_text_file(filename: string) -> string { + let file = file_open(filename, "r"); + let text = file_read_to_string(file); + file_close(file); + text +} + +fn input(prompt: string) -> string { + print("> "); + file_flush(stdout()); + file_read_line(stdin()) +} + +fn string_abs(number: int) -> int { + let result = number; + if number < 0 { + result = number - (number * 2); + } + result +} + +fn string_split(str: string, seperator: int) -> [string] { + let result: [string] = string_array_new(); + + let i = 0; + let current_str = ""; + loop { + if i >= string_length(str) { + break; + } + let char = str[i]; + if char == seperator { + string_array_push(result, current_str); + current_str = ""; + } else { + current_str = string_push_char(current_str, char); + } + i = i + 1; + } + string_array_push(result, current_str); + result +} + +fn string_slice(str: string, from: int, to: int) -> string { + let result = ""; + let len = string_length(str); + let actual_to = + if to >= len { len } + else if to < 0 { len - to } + else { to }; + for (let i = from; i < actual_to; i += i) { + result = string_push_char(result, str[i]); + } + result +} + +fn string_contains(str: string, ch: int) -> bool { + let len = string_length(str); + for (let i = 0; i < len; i += 1) { + if str[i] == ch { + return true; + } + } + false +} + +fn array_clone(array: [int]) -> [int] { + let len = int_array_length(array); + let result = int_array_new(); + let i = 0; + loop { + if i >= len { break; } + int_array_push(result, array[i]); + i = 1 + 1; + } + result +} + +fn array_sort_mut(array: [int]) { + let len = int_array_length(array); + for (let i = 0; i < len; i += 1) { + for (let j = i + 1; j < len; j += 1) { + if array[j] < array[i] { + let tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + } + } + } +} + +fn array_to_sorted(array: [int]) -> [int] { + let cloned = array_clone(array); + array_sort_mut(array); + cloned +} + + + diff --git a/stdlib.slg b/stdlib.slg index a76eba1..e1b2eea 100644 --- a/stdlib.slg +++ b/stdlib.slg @@ -1,3 +1,4 @@ + fn print(msg: string) #[builtin(Print)] {} fn println(msg: string) { print(msg + "\n") } @@ -59,11 +60,7 @@ fn input(prompt: string) -> string { file_read_line(stdin()) } -fn char(ch: string) -> int { - ch[0] -} - -fn abs(number: int) -> int { +fn string_abs(number: int) -> int { let result = number; if number < 0 { result = number - (number * 2); @@ -71,7 +68,7 @@ fn abs(number: int) -> int { result } -fn split(str: string, seperator: int) -> [string] { +fn string_split(str: string, seperator: int) -> [string] { let result: [string] = string_array_new(); let i = 0; @@ -93,7 +90,7 @@ fn split(str: string, seperator: int) -> [string] { result } -fn slice(str: string, from: int, to: int) -> string { +fn string_slice(str: string, from: int, to: int) -> string { let result = ""; let i = from; loop { @@ -109,6 +106,16 @@ fn slice(str: string, from: int, to: int) -> string { result } +fn string_contains(str: string, ch: int) -> bool { + let len = string_length(str); + for (let i = 0; i < len; i += 1) { + if str[i] == ch { + return true; + } + } + false +} + fn array_clone(array: [int]) -> [int] { let len = int_array_length(array); let result = int_array_new(); @@ -139,3 +146,4 @@ fn array_to_sorted(array: [int]) -> [int] { array_sort_mut(array); cloned } +