summaryrefslogtreecommitdiff
path: root/chapter25/src
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/Parser.java26
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java13
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Simple.java5
3 files changed, 36 insertions, 8 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/Parser.java b/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
index 98f8698f..4c2dfc84 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
@@ -2396,11 +2396,27 @@ public class Parser {
private String parseString() {
if( !peek('"') ) return null;
_lexer.inc();
- int start = pos();
- while( !_lexer.isEOF() && _lexer.nextChar()!= '"' ) ;
- if( _lexer.isEOF() )
- throw error("Unclosed string");
- return new String(_lexer._input,start,pos()-start-1);
+ StringBuilder sb = new StringBuilder();
+ while( !_lexer.isEOF() ) {
+ char c = _lexer.nextChar();
+ if( c=='"' ) return sb.toString();
+ if( c!='\\' ) {
+ sb.append(c);
+ continue;
+ }
+ if( _lexer.isEOF() )
+ throw error("Unclosed string");
+ char esc = _lexer.nextChar();
+ sb.append(switch( esc ) {
+ case 'n' -> '\n';
+ case 't' -> '\t';
+ case 'r' -> '\r';
+ case '\\' -> '\\';
+ case '"' -> '"';
+ default -> throw error("Unknown string escape \\\\"+esc);
+ });
+ }
+ throw error("Unclosed string");
}
// Already parsed "'"
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
index cf9d764e..313ae1cf 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter25Test.java
@@ -38,6 +38,15 @@ public class Chapter25Test {
assertEquals("1",Eval2.eval(code,0));
}
+ @Test
+ public void testStringEscapes() {
+ String src = "u8[~] s=\"A\\n\\t\\r\\\\\\\"B\"; " +
+ "return s#==7 && s[0]=='A' && s[1]==10 && s[2]==9 && s[3]==13 && " +
+ "s[4]==92 && s[5]==34 && s[6]=='B';";
+ CodeGen code = new CodeGen(src).driver(CodeGen.Phase.TypeCheck);
+ assertEquals("1",Eval2.eval(code,0));
+ }
+
@Test @Ignore
public void testModule0() throws IOException {
@@ -197,7 +206,7 @@ public class Chapter25Test {
File sys_file = buildTestSys(false);
assertTrue("Missing "+sys_file+"; testHelloWorld depends on testSys building it", sys_file.exists());
- String expected = "Hello, World!";
+ String expected = "Hello, World!\n";
String prog = "return sys.io.p(\""+expected+"\") - "+expected.length()+";";
TestC.run(prog,"helloWorld",new Ary<>(new String[]{SYS_BLDDIR}),
TestC.CALL_CONVENTION, null, null, expected,0);
@@ -223,7 +232,7 @@ public class Chapter25Test {
assertTrue("Missing "+sys_file+"; testHelloWorldNoInline depends on testSys building it", sys_file.exists());
String base = "helloWorldNoInline";
- String expected = "Hello, World!";
+ String expected = "Hello, World!\n";
String prog = "return sys.io.p_noInline(\""+expected+"\") - "+expected.length()+";";
CodeGen code = new CodeGen(null,"build/objs",new Ary<>(new String[]{SYS_BLDDIR}),
base,prog,123L,TypeInteger.BOT);
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Simple.java b/chapter25/src/test/java/com/seaofnodes/simple/Simple.java
index 870792c0..35b9b922 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Simple.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Simple.java
@@ -35,6 +35,7 @@ Options:
-L path - add an external Simple object search path
--eval - (slowly) evaluate the compiled code in emulator
--run - run the compiled code natively; this is the default
+ --main - export the top-level initializer as C `main`
--cpu <cpu-name> - use specific CPU (x86_64_v2, riscv, arm)
--abi <abi-name> - use specific ABI variant (SystemV)
--target - print native CPU and ABI
@@ -89,6 +90,7 @@ Options:
boolean do_eval = false;
boolean do_run = true;
boolean do_codegen = false;
+ boolean emit_main = false;
boolean dump_dot = false;
boolean print_time = false;
boolean print_size = false;
@@ -129,6 +131,7 @@ Options:
case "--eval": do_eval = true ; do_run = false; break;
case "--run": do_run = true ; break;
case "--norun": do_run = false; break;
+ case "--main": emit_main = true; break;
case "--dump-size": print_size = true; break;
case "--dump-time": print_time = true; break;
case "-o": if (out != null || i + 1 >= args.length || args[i + 1].charAt(0) == '-') bad_usage();
@@ -221,7 +224,7 @@ Options:
// Compilation pipeline
Ary<String> externPaths = libPaths.isEmpty() ? null : new Ary<>(libPaths.toArray(new String[0]));
CodeGen code = new CodeGen(modPath.toString(), outPath.toString(), externPaths, srcName, src, 456, TypeInteger.BOT );
- code.driver(Phase.LastPhase,cpu,abi, false, do_run || do_eval, dump);
+ code.driver(Phase.LastPhase,cpu,abi, false, emit_main || do_run || do_eval, dump);
if( do_codegen && print_asm )
System.out.println(code.asm());