Skip to content

Commit

Permalink
Shoe horn first updates for return syntax error from top-level as wel…
Browse files Browse the repository at this point in the history
…l as

fixing a bug with inDef noticing it is still inDef after evaluating a nested
def.
enebo committed Mar 28, 2018
1 parent 3242f49 commit a6d4ec3
Showing 5 changed files with 4,903 additions and 4,754 deletions.
3 changes: 2 additions & 1 deletion core/src/main/java/org/jruby/lexer/yacc/SyntaxException.java
Original file line number Diff line number Diff line change
@@ -60,7 +60,8 @@ public enum PID {
NUL_IN_SYMBOL("NUL_IN_SYMBOL"),
REGEXP_ENCODING_MISMATCH("REGEXP_ENCODING_MISMATCH"),
INVALID_MULTIBYTE_CHAR("INVALID_MULTIBYTE_CHAR"),
RATIONAL_OUT_OF_RANGE("RATIONAL_OUT_OF_RANGE")
RATIONAL_OUT_OF_RANGE("RATIONAL_OUT_OF_RANGE"),
TOP_LEVEL_RETURN("TOP_LEVEL_RETURN")
;

private String id;
22 changes: 22 additions & 0 deletions core/src/main/java/org/jruby/parser/ParserSupport.java
Original file line number Diff line number Diff line change
@@ -80,6 +80,9 @@ public class ParserSupport {
// Is the parser currently within a method definition
private boolean inDefinition;

// Is the parser currently within a class body.
private boolean inClass;

protected IRubyWarnings warnings;

protected ParserConfiguration configuration;
@@ -1050,6 +1053,25 @@ public void setInDef(boolean inDef) {
this.inDefinition = inDef;
}

public boolean isInClass() {
return inClass;
}

public void setIsInClass(boolean inClass) {
this.inClass = inClass;
}

/**
* Is the top of this scope a block scope (which happens in evals).
* This is supposed to serve same purpose as MRIs: dyna_in_block but
* I don't quite get why it is so complicated. All non-eval parsers
* have local scopes except eval but they combine in_main || compile_for_eval?
*/
public boolean isBlockTopLevel() {
return getConfiguration().isEvalParse();
}


/** Getter for property inSingle.
* @return Value of property inSingle.
*/
1,453 changes: 748 additions & 705 deletions core/src/main/java/org/jruby/parser/RubyParser.java

Large diffs are not rendered by default.

54 changes: 41 additions & 13 deletions core/src/main/java/org/jruby/parser/RubyParser.y
Original file line number Diff line number Diff line change
@@ -290,6 +290,7 @@ public class RubyParser {
%type <ArgumentNode> f_arg_asgn
%type <FCallNode> fcall
%token <ByteList> tLABEL_END, tSTRING_DEND
%type <ISourcePosition> k_return k_class k_module

/*
* precedence table
@@ -599,7 +600,7 @@ command : fcall command_args %prec tLOWEST {
| keyword_yield command_args {
$$ = support.new_yield($1, $2);
}
| keyword_return call_args {
| k_return call_args {
$$ = new ReturnNode($1, support.ret_args($2, $1));
}
| keyword_break call_args {
@@ -1497,7 +1498,7 @@ primary : literal
| tLBRACE assoc_list tRCURLY {
$$ = $2;
}
| keyword_return {
| k_return {
$$ = new ReturnNode($1, NilImplicitNode.NIL);
}
| keyword_yield tLPAREN2 call_args rparen {
@@ -1570,19 +1571,22 @@ primary : literal
// ENEBO: Lots of optz in 1.9 parser here
$$ = new ForNode($1, $2, $8, $5, support.getCurrentScope());
}
| keyword_class cpath superclass {
if (support.isInDef() || support.isInSingle()) {
| k_class cpath superclass {
if (support.isInDef()) {
support.yyerror("class definition in method body");
}
support.pushLocalScope();
$$ = support.isInClass(); // MRI reuses $1 but we use the value for position.
support.setIsInClass(true);
} bodystmt keyword_end {
Node body = support.makeNullNil($5);

$$ = new ClassNode($1, $<Colon3Node>2, support.getCurrentScope(), body, $3, lexer.getRubySourceline());
support.popCurrentScope();
support.setIsInClass($<Boolean>4.booleanValue());
}
| keyword_class tLSHFT expr {
$$ = Boolean.valueOf(support.isInDef());
| k_class tLSHFT expr {
$$ = new Integer((support.isInClass() ? 2 : 0) & (support.isInDef() ? 1 : 0));
support.setInDef(false);
} term {
$$ = Integer.valueOf(support.getInSingle());
@@ -1593,35 +1597,43 @@ primary : literal

$$ = new SClassNode($1, $3, support.getCurrentScope(), body, lexer.getRubySourceline());
support.popCurrentScope();
support.setInDef($<Boolean>4.booleanValue());
support.setInDef((($<Integer>4.intValue()) & 1) != 0);
support.setIsInClass((($<Integer>4.intValue()) & 2) != 0);
support.setInSingle($<Integer>6.intValue());
}
| keyword_module cpath {
if (support.isInDef() || support.isInSingle()) {
| k_module cpath {
if (support.isInDef()) {
support.yyerror("module definition in method body");
}
$$ = support.isInClass();
support.setIsInClass(true);
support.pushLocalScope();
} bodystmt keyword_end {
Node body = support.makeNullNil($4);

$$ = new ModuleNode($1, $<Colon3Node>2, support.getCurrentScope(), body, lexer.getRubySourceline());
support.popCurrentScope();
support.setIsInClass($<Boolean>3.booleanValue());
}
| keyword_def fname {
support.setInDef(true);
support.pushLocalScope();
$$ = lexer.getCurrentArg();
lexer.setCurrentArg(null);
} {
$$ = support.isInDef();
support.setInDef(true);
} f_arglist bodystmt keyword_end {
Node body = support.makeNullNil($5);
Node body = support.makeNullNil($6);

$$ = new DefnNode($1, $2, (ArgsNode) $4, support.getCurrentScope(), body, $6.getLine());
$$ = new DefnNode($1, $2, (ArgsNode) $5, support.getCurrentScope(), body, $7.getLine());
support.popCurrentScope();
support.setInDef(false);
support.setInDef($<Boolean>4.booleanValue());
lexer.setCurrentArg($<ByteList>3);
}
| keyword_def singleton dot_or_colon {
lexer.setState(EXPR_FNAME);
$$ = support.isInDef();
support.setInDef(true);
} fname {
support.setInSingle(support.getInSingle() + 1);
support.pushLocalScope();
@@ -1635,6 +1647,7 @@ primary : literal
$$ = new DefsNode($1, $2, $5, (ArgsNode) $7, support.getCurrentScope(), body, $9.getLine());
support.popCurrentScope();
support.setInSingle(support.getInSingle() - 1);
support.setInDef($<Boolean>4.booleanValue());
lexer.setCurrentArg($<ByteList>6);
}
| keyword_break {
@@ -1656,6 +1669,21 @@ primary_value : primary {
if ($$ == null) $$ = NilImplicitNode.NIL;
}

k_class : keyword_class {
$$ = $1;
}

k_module : keyword_module {
$$ = $1;
}

k_return : keyword_return {
if (support.isInClass() && !support.isInDef() && !support.getCurrentScope().isBlockScope()) {
lexer.compile_error(PID.TOP_LEVEL_RETURN, "Invalid return in class/module body");
}
$$ = $1;
}

then : term
| keyword_then
| term keyword_then
8,125 changes: 4,090 additions & 4,035 deletions core/src/main/java/org/jruby/parser/YyTables.java

Large diffs are not rendered by default.

0 comments on commit a6d4ec3

Please sign in to comment.