# HG changeset patch # User Anders Johnsen # Date 1209925621 -7200 # Node ID a49bb982a7b0feb9580bfecdd7b2ebf18c98e07c # Parent eb5b2c719a39a551f244d8797d971d1d54448ff7 Using the new SourceLocation system to handle errors. Also, this is the first push for making the errors don't throw, but continue to check the source. diff -r eb5b2c719a39 -r a49bb982a7b0 basic/Message.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/basic/Message.d Sun May 04 20:27:01 2008 +0200 @@ -0,0 +1,157 @@ +module basic.Message; + +import tango.core.Exception, + Array = tango.core.Array, + tango.io.Stdout, + tango.text.Util; + +import tango.stdc.stdlib; + +import llvm.type; + +import lexer.Token, + lexer.Lexer, + sema.DType, + sema.Symbol; + +import basic.SourceLocation, + basic.SourceManager; + +public import basic.Messages; + +class MessageHandler +{ +public: + + this(SourceManager src_mgr) + { + this.src_mgr = src_mgr; + } + + Message report(uint opcode, SLoc location, bool fatal = false) + { + Message m = new Message(opcode, location, src_mgr); + messages ~= m; + if(fatal) + checkErrors(); + return m; + } + + void checkErrors() + { + if(messages.length == 0) + return; + + foreach(m ; messages) + if(m.type == MessageType.Error) + { + Stdout(m).newline; + } + + exit(1); + } + + void checkWarnings() + { + } + + void showWarnings(bool value) + { + warnings = value; + } + +private: + Message[] messages; + SourceManager src_mgr; + bool warnings; +} + +class Message +{ + + this(int opcode, SLoc location, SourceManager src_mgr) + { + this.src_mgr = src_mgr; + this.location = location; + args ~= Messages[opcode].message; + this.type = Messages[opcode].type; + } + + char[] toString() + { + char[256] tmp = void; + char[] msg = layout(tmp, args); + + Lexer l = new Lexer(location, src_mgr, new MessageHandler(src_mgr)); + + Token t = l.next; + + if (src_mgr.getRawData(location).length > 0) + msg = src_mgr.getLocationAsString(location) ~ ": " ~ msg; + else + msg = msg.dup; + + + char[] line = src_mgr.getLine(location); + char[] marks = line.dup; + marks[] = ' '; + size_t p = src_mgr.getOffsetToLine(location); + marks[p .. p + t.length] = '^'; + + msg ~= "\n "; + msg ~= line; + msg ~= "\n "; + msg ~= marks; + + return msg; + } + + Message arg(char[] s) + { + if (args.length == 11) + throw new Exception("Sorry, errors only support up to 10 args"); + args ~= s; + return this; + } + + Message arg(char[][] s) + { + char[] res = s[0 .. $ - 1].join(", "); + if (s.length > 1) + res ~= " and "; + res ~= s[$ - 1]; + return arg(res); + } + + Message arg(char c) + { + return arg([c]); + } + + Message arg(DType[] types) + { + char[][] res; + foreach (type; types) + res ~= type.name(); + return arg(res); + } + + Message arg(Symbol sym) + { + return arg(sym.type.name ~ " " ~ sym.id.get); + } + + /* + Message loc(SLoc loc) + { + location = loc; + return this; + } + */ + + MessageType type; +private: + char[][] args; + SLoc location; + SourceManager src_mgr; +} diff -r eb5b2c719a39 -r a49bb982a7b0 basic/Messages.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/basic/Messages.d Sun May 04 20:27:01 2008 +0200 @@ -0,0 +1,54 @@ +module basic.Messages; + +enum : uint +{ + InvalidType, + InvalidSymbol, + InvalidIlligaleType, + UnexpectedEOFBlock, + OnlyOneDotFloating, + OnlyOneEFloating, + UnexpectedTokMulti, + UnexpectedTokSingle, + UnexpectedTok, + CaseValueMustBeInt, + UnexpectedBeginStmt, + UnexpectedTokType, + ExpectedIdAfterDot, + ExpectedExp, + ExpectedCastType +} + +enum MessageType +{ + Warning, + Error, +} + +MessageEntry[uint] Messages; + +struct MessageEntry +{ + MessageType type; + char[] message; +} + +static this() +{ + Messages = [ + InvalidType : MessageEntry(MessageType.Error, "InvalidType"), + UnexpectedEOFBlock : MessageEntry(MessageType.Error, "Unexpected end of file. Unclosed comment block"), + InvalidSymbol : MessageEntry(MessageType.Error, "Read invalid symbol: '%0'"), + OnlyOneDotFloating : MessageEntry(MessageType.Error, "Only one '.' is allowed in an floating number"), + OnlyOneEFloating : MessageEntry(MessageType.Error, "Only one E is allowed in an floating number"), + UnexpectedTokMulti : MessageEntry(MessageType.Error, "Unexpected token, got %0 expected one of %1"), + UnexpectedTokSingle : MessageEntry(MessageType.Error, "Unexpected token, got %0 expected %1"), + UnexpectedTok : MessageEntry(MessageType.Error, "Unexpected token %0"), + CaseValueMustBeInt : MessageEntry(MessageType.Error, "Cases can only be integer literals"), + UnexpectedBeginStmt : MessageEntry(MessageType.Error, "Unexpected begining of statement."), + UnexpectedTokType : MessageEntry(MessageType.Error, "Unexpected token in Type parsing. Got %0"), + ExpectedIdAfterDot : MessageEntry(MessageType.Error, "Expected identifier after '.'"), + ExpectedExp : MessageEntry(MessageType.Error, "Expected expression"), + ExpectedCastType : MessageEntry(MessageType.Error, "Expected cast type") + ]; +} diff -r eb5b2c719a39 -r a49bb982a7b0 basic/SourceManager.d --- a/basic/SourceManager.d Sun May 04 18:13:46 2008 +0200 +++ b/basic/SourceManager.d Sun May 04 20:27:01 2008 +0200 @@ -88,7 +88,23 @@ --ptr_lo; while (ptr != cp.data.ptr + cp.data.length && *ptr != '\n' && *ptr != '\r') ++ptr; - return ptr_lo[0 .. ptr - ptr_lo]; + return ptr_lo[1 .. ptr - ptr_lo]; + } + + /** + Extracts a string containing the entire line loc appears in. + **/ + int getOffsetToLine(SourceLocation loc) + { + // The line is extracted by getting two pointers to the exact location + // and decreasing one until the nearest newline while the other ptr is + // increased to the nearest newline. + CP* cp = &checkpoints[loc.fileID]; + char* ptr = cp.data.ptr + loc.fileOffset; + char* ptr_lo = ptr; + while (ptr_lo != cp.data.ptr && *ptr_lo != '\n' && *ptr_lo != '\r') + --ptr_lo; + return cast(int)ptr - cast(int)ptr_lo - 1; } /** diff -r eb5b2c719a39 -r a49bb982a7b0 dang/compiler.d --- a/dang/compiler.d Sun May 04 18:13:46 2008 +0200 +++ b/dang/compiler.d Sun May 04 20:27:01 2008 +0200 @@ -2,7 +2,9 @@ import tango.io.Stdout, tango.core.Signal, + tango.sys.Process, tango.time.StopWatch, + tango.io.FileConduit, tango.io.FilePath; import lexer.Lexer, @@ -10,6 +12,8 @@ import basic.SourceManager; +import basic.Message; + import ast.Decl; import tools.AstPrinter, @@ -85,6 +89,10 @@ bool optimize = false; bool inline = false; + + SourceManager src_mgr = new SourceManager; + MessageHandler messages = new MessageHandler(src_mgr); + argParse.addOption(["-h", "--help"], Opt.Action.Help) .help("Show this help message"); @@ -94,10 +102,12 @@ argParse.addOption(["--ast-dump-code"], "what-to-do", Opt.Action.StoreConst, "code") .help("Output the AST as code"); - argParse.addOption(["--gen-llvm"], "what-to-do", Opt.Action.StoreConst, "gen-llvm") .help("Compile to LLVM code (default)"); + argParse.addOption(["-c"], + "what-to-do", Opt.Action.StoreConst, "compile") + .help("Compile to .o or executeable"); argParse.addOption( ["-O","--optimize"], { @@ -131,9 +141,19 @@ (Decl[] decls, SourceManager sm) { StopWatch w; w.start; auto llvmGen = new CodeGen(); - llvmGen.gen(decls, optimize, inline); + auto file = new FileConduit("out.bc"); + llvmGen.gen(decls, file.fileHandle, optimize, inline); timings ~= Measurement("Generating LLVM bytecode", w.stop); }); + else if (what == "compile") + postParse.attach( + (Decl[] decls, SourceManager sm) { + StopWatch w; w.start; + auto llvmGen = new CodeGen(); + auto llc = new Process("llc"); + llvmGen.gen(decls, llc.stdin.fileHandle, optimize, inline); + timings ~= Measurement("Generating assemble bytecode", w.stop); + }); else if (what == "dot") postParse.attach( (Decl[] decls, SourceManager sm) { @@ -150,9 +170,6 @@ print.print(decls); timings ~= Measurement("Converting AST to text", w.stop); }); - - SourceManager src_mgr = new SourceManager; - StopWatch total; total.start; foreach (file; filesToHandle) @@ -160,18 +177,18 @@ preLex(file); auto start = src_mgr.addFile(file); - Stdout(file).newline; - auto lexer = new Lexer(start, src_mgr); + auto lexer = new Lexer(start, src_mgr, messages); postLex(lexer); preParse(lexer); StopWatch watch; watch.start; - auto parser = new Parser; + auto parser = new Parser(messages); auto action = new AstAction(src_mgr); auto decls = cast(Decl[])parser.parse(src_mgr, lexer, action); timings ~= Measurement("Lex + Parse", watch.stop); + messages.checkErrors(); StopWatch watch2; watch.start; diff -r eb5b2c719a39 -r a49bb982a7b0 gen/CodeGen.d --- a/gen/CodeGen.d Sun May 04 18:13:46 2008 +0200 +++ b/gen/CodeGen.d Sun May 04 20:27:01 2008 +0200 @@ -65,7 +65,7 @@ b.dispose(); } - void gen(Decl[] decls, bool optimize, bool inline) + void gen(Decl[] decls, uint handle, bool optimize, bool inline) { // create module m = new Module("main_module"); @@ -89,7 +89,7 @@ Type pointer = PointerType.Get(llvm(st)); param_types ~= pointer; } - if(auto ar = t.asArray) + else if(auto ar = t.asArray) { Type pointer = PointerType.Get(llvm(ar)); param_types ~= pointer; @@ -141,7 +141,7 @@ if(optimize) m.optimize(inline); - m.writeBitcodeToFile("out.bc"); + m.writeBitcodeToFileHandle(handle); } void genRootDecl(Decl decl) @@ -531,7 +531,6 @@ else assert(0, "Can only index pointers and arrays"); case ExpType.MemberReference: auto mem = cast(MemberReference)exp; - Stdout(mem.target).newline; switch(mem.target.expType) { case ExpType.Identifier: diff -r eb5b2c719a39 -r a49bb982a7b0 lexer/Lexer.d --- a/lexer/Lexer.d Sun May 04 18:13:46 2008 +0200 +++ b/lexer/Lexer.d Sun May 04 20:27:01 2008 +0200 @@ -1,6 +1,6 @@ module lexer.Lexer; -import misc.Error, +import basic.Message, basic.SourceManager; import lexer.Token, @@ -21,8 +21,11 @@ /** Create a new Lexer. */ - this(SourceLocation start, SourceManager src_mgr) + + + this(SourceLocation start, SourceManager src_mgr, MessageHandler messages) { + this.messages = messages; sm = src_mgr; start_loc = start; position = 0; @@ -112,16 +115,6 @@ return t; } - /** - Return all errors that occurred while tokenizing the string. - - TODO: Error system not implemented yet - this is a stub! - */ - public Error[] getErrors() - { - return this.errors; - } - private: Token eq() { @@ -231,7 +224,7 @@ if(source[position-1] == '/') return this.next; } - throw error(__LINE__, "Unexpected end of file. Unclosed comment block"); + messages.report(UnexpectedEOFBlock,Loc(position)); case '+': position += 2; @@ -256,7 +249,7 @@ if(nesting == 0) return this.next; } - throw error(__LINE__, "Unexpected end of file. Unclosed comment block"); + messages.report(UnexpectedEOFBlock,Loc(position)); default: return Token(Tok.Slash, Loc(position - 1), 1); @@ -287,8 +280,7 @@ if(this.source[position+i] == '.') { if(dot) - throw error(__LINE__,"Only one '.' is allowed in an floating number") - .tok(Token(Tok.Float, Loc(position + i), 1)); + messages.report(OnlyOneDotFloating, Loc(position + i)); dot = true; break; } @@ -301,8 +293,7 @@ this.source[position+i] == 'E') { if (e) - throw error(__LINE__,"Only one '"~this.source[position+i] - ~"' is allowed in an floating number"); + messages.report(OnlyOneEFloating, Loc(position + i)); e = true; break; } @@ -365,17 +356,12 @@ CharType c = charTable[current]; if(c == CharType.INVALID) - throw error(__LINE__, "Read invalid symbol: '%0'").arg(current); + messages.report(InvalidSymbol, SLoc()).arg(current); return c; } - Error error(uint line, char[] msg) - { - return (new Error(msg));//.loc(Loc(position)); - } - private final SourceLocation Loc(int pos = -1) { if (pos < 0) @@ -387,7 +373,7 @@ SourceLocation start_loc; int position; char[] source; - Error[] errors; + MessageHandler messages; CharType[] charTable; Token delegate()[] symbolFunctions; } diff -r eb5b2c719a39 -r a49bb982a7b0 parser/Parser.d --- a/parser/Parser.d Sun May 04 18:13:46 2008 +0200 +++ b/parser/Parser.d Sun May 04 20:27:01 2008 +0200 @@ -5,7 +5,7 @@ import parser.Action; -import misc.Error; +import basic.Message; import basic.SmallArray, basic.SourceManager; @@ -16,11 +16,18 @@ class Parser { Action action; + MessageHandler messages; alias Object Exp; alias Object Stmt; alias Object Decl; public: + + this(MessageHandler messages) + { + this.messages = messages; + } + Decl[] parse(SourceManager sm, Lexer lexer, Action act) { this.sm = sm; @@ -59,9 +66,7 @@ else if (next.type == Tok.OpenParentheses) return parseFunc(type, iden); else - throw error(__LINE__, PE.UnexpectedTok) - .tok(next) - .arg(next.getType); + messages.report(UnexpectedTok, next.location).arg(next.getType); } else if (t.type == Tok.Struct) { @@ -70,8 +75,7 @@ return parseStruct(type, iden); } - char[] c = t.getType; - throw error(__LINE__, PE.UnexpectedTok).tok(t).arg(c); + messages.report(UnexpectedTok, t.location).arg(t.getType); } /** @@ -102,8 +106,7 @@ action.actOnStructMember(decl, var_type, var_iden, exp); continue; } - throw error(__LINE__, PE.UnexpectedTok) - .tok(next).arg(next.getType); + messages.report(UnexpectedTok, next.location).arg(next.getType); } require(Tok.CloseBrace); @@ -187,7 +190,7 @@ if ( n.type == Tok.Star || n.type == Tok.OpenBracket) { int len = peekParseType; - if(lexer.peek(len).type == Tok.Identifier || len == 0) + if(lexer.peek(len).type == Tok.Identifier && len != 0) return action.actOnDeclStmt(parseVarDecl()); Exp exp = parseExpression(); @@ -206,7 +209,7 @@ } case Tok.Switch: - throw error(__LINE__, ":(").tok(lexer.peek); + messages.report(UnexpectedTok, lexer.peek.location).arg(lexer.next.getType); return null; default: @@ -218,10 +221,9 @@ require(Tok.Seperator); return action.actOnExprStmt(exp); } - - throw error(__LINE__, "Unexpexted begining of statement.").tok(lexer.peek); + messages.report(UnexpectedBeginStmt, lexer.peek.location).arg(lexer.next.getType); } - throw error(__LINE__, "").tok(t); + messages.report(UnexpectedTok, t.location); return null; } @@ -313,10 +315,9 @@ if (tok.type is Tok.Identifier) return Id(tok); - throw error(__LINE__, PE.UnexpectedTokSingle) + messages.report(UnexpectedTokSingle, tok.location) .arg(tok.getType) - .arg(Tok.Identifier) - .tok(tok); + .arg(Tok.Identifier); } /** @@ -329,9 +330,8 @@ Id currentType; if ( !(type.isBasicType || type.type == Tok.Identifier) ) - throw error(__LINE__, "Unexpected token in Type parsing. Got %0") - .arg(type.getType) - .tok(type); + messages.report(UnexpectedTokSingle, type.location) + .arg(type.getType); currentType = Id(type); type = lexer.peek; @@ -364,7 +364,7 @@ Id currentType; if ( !(type.isBasicType || type.type == Tok.Identifier) ) - return i; + return 0; currentType = Id(type); type = lexer.peek(++i); @@ -407,7 +407,7 @@ return parsePostfixExp(exp); default: Token t = lexer.peek(1); - throw error(__LINE__, "Expected identifier after '.'").tok(t); + messages.report(ExpectedIdAfterDot, t.location); } case Tok.OpenBracket: Token open = lexer.next; @@ -475,10 +475,9 @@ else if (next.type == Tok.Integer) return action.actOnNumericConstant(next); - throw error(__LINE__, "Expected expression, not '%0'") - .tok(next) - .arg(next.getType); - assert(0, "Should not happen"); + messages.report(ExpectedExp, next.location, true); +// assert(0, "Should not happen"); + return null; } Exp parseCast(ref Token _cast) @@ -486,9 +485,7 @@ require(Tok.OpenParentheses); auto next = lexer.next; if(!next.isBasicType && !next.isIdentifier) - throw error(__LINE__, "Expected cast type, not %0") - .tok(next) - .arg(next.getType); + messages.report(ExpectedCastType, next.location); require(Tok.CloseParentheses); auto exp = P(); @@ -554,10 +551,9 @@ Token require(Tok t) { if (lexer.peek().type != t) - throw error(__LINE__, PE.UnexpectedTokSingle) + messages.report(UnexpectedTokSingle, lexer.peek.location) .arg(lexer.peek.getType) - .arg(t) - .tok(lexer.peek); + .arg(t); return lexer.next(); } @@ -569,26 +565,6 @@ return true; } - Error error(uint line, char[] errMsg) - { - SLoc loc = lexer.peek.location; - auto e = - new Error("Parser.d(" ~ Integer.toString(line) ~ "): " ~errMsg); - //e.loc(loc); - return e; - } - - struct PE - { - static char[] - UnexpectedTokMulti = "Unexpected token, got %0 expected one of %1", - UnexpectedTokSingle = "Unexpected token, got %0 expected %1", - UnexpectedTok = "Unexpected token %0"; - - static char[] - CaseValueMustBeInt = "Cases can only be integer literals"; - } - Lexer lexer; SourceManager sm; } diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/basic_2.d --- a/tests/code/basic_2.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/basic_2.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main() { int x = y; diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/func_1.d --- a/tests/code/func_1.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/func_1.d Sun May 04 20:27:01 2008 +0200 @@ -11,6 +11,7 @@ testStruct m(testStruct t) { t.x = t.x - 5; + return t; } struct testStruct diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/math_3.d --- a/tests/code/math_3.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/math_3.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main() { int x = x; diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/scope_1.d --- a/tests/code/scope_1.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/scope_1.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main() { int x = y; diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/scope_2.d --- a/tests/code/scope_2.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/scope_2.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main() { int x = 10; diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/switch_5.d --- a/tests/code/switch_5.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/switch_5.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main(int x) { switch (x) diff -r eb5b2c719a39 -r a49bb982a7b0 tests/code/switch_6.d --- a/tests/code/switch_6.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/code/switch_6.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test fail +//fail int main(int x) { switch (x) diff -r eb5b2c719a39 -r a49bb982a7b0 tests/lexer/Comments2.d --- a/tests/lexer/Comments2.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/lexer/Comments2.d Sun May 04 20:27:01 2008 +0200 @@ -1,4 +1,4 @@ -//test failure +//fail /+ diff -r eb5b2c719a39 -r a49bb982a7b0 tests/run.d --- a/tests/run.d Sun May 04 18:13:46 2008 +0200 +++ b/tests/run.d Sun May 04 20:27:01 2008 +0200 @@ -13,6 +13,14 @@ tango.sys.Process; +enum +{ + SuccessSuccess, + SuccessFailure, + FailureSuccess, + FailureFailure, +} + char[] prog = "./Dang"; void main(char[][] args) @@ -39,16 +47,16 @@ switch(result) { - case 0: + case SuccessSuccess: success_success++; break; - case 1: + case SuccessFailure: success_failure++; break; - case 2: + case FailureFailure: failure_failure++; break; - case 3: + case FailureSuccess: failure_success++; break; } @@ -58,15 +66,28 @@ Stdout().newline.newline() ("Result:").newline() - (" - Succes/Success: ")(success_success).newline() - (" - Succes/Failure: ")(success_failure).newline() + (" - Success/Success: ")(success_success).newline() + (" - Success/Failure: ")(success_failure).newline() (" - Failure/Failure: ")(failure_failure).newline() (" - Failure/Success: ")(failure_success).newline; } class Test { + enum TestValue + { + Success = 0, + Lexer = 2, + Parser = 3, + Gen = 4, + + Fail = 100 + } + FilePath target; + + TestValue[int] testValues; + public this(FilePath target) { this.target = target; @@ -78,10 +99,25 @@ auto file = new UnicodeFile!(char)(target.path~target.file, Encoding.UTF_8); - int mode; + TestValue mode; char[] data = file.read; - if(data.length > 6 && data[0..6] == "//test") + char[][] commands = split(splitLines(data)[0], " "); + if(commands[0] == "//fail") + { + mode = TestValue.Fail; + if(commands.length > 1) + { + try + { + int i = Integer.toInt(commands[1]); + if(i in testValues) + mode = testValues[i]; + } + catch{} + } + } +/* if(data.length > 6 && data[0..6] == "//fail") { char[] str = data.splitLines()[0][6..$]; @@ -95,7 +131,7 @@ mode = 0; } } - +*/ Stdout.format(" {,-25}", target.file); process.execute; @@ -115,7 +151,7 @@ return resultOf(result.status, mode); } - private int resultOf(int status, int mode) + private int resultOf(int status, TestValue mode) { char[] good(char[] s) { @@ -135,28 +171,28 @@ if(status == 0) { - if(mode == 0) + if(mode == TestValue.Success) { - Stdout(good("SUCCES")).newline; - return 0; + Stdout(good("SUCCESS")).newline; + return SuccessSuccess; } - if(mode == 1) + if(mode == TestValue.Fail) { - Stdout(bad("SUCCES - Unexpected")).newline; - return 3; + Stdout(bad("SUCCESS - Unexpected")).newline; + return FailureSuccess; } } else { - if(mode == 1) + if(mode == TestValue.Fail) { Stdout(good("FAILURE")).newline; - return 2; + return FailureFailure; } - if(mode == 0) + if(mode == TestValue.Success) { Stdout(bad("FAILURE - Unexpected")).newline; - return 1; + return SuccessFailure; } } }