Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

lexer: made flags per-nest; fixes #200

  • Loading branch information...
commit 0fd717fc03b8b3931c4d1f810e7432de79ab6fed 1 parent 85d7168
@satyr authored
Showing with 84 additions and 36 deletions.
  1. +35 −16 lib/lexer.js
  2. +40 −14 src/lexer.co
  3. +9 −6 test/loop.co
View
51 lib/lexer.js
@@ -24,6 +24,7 @@ exports.tokenize = function(code, o){
this.dents = [];
this.closes = [];
this.parens = [];
+ this.flags = [];
i = 0;
while (c = code.charAt(i)) {
switch (c) {
@@ -136,12 +137,13 @@ exports.doID = function(code, index){
case 'super':
return this.token('LITERAL', id, true).length;
case 'for':
- this.seenFor = true;
- this.wantBy = false;
id = [];
+ this.fset('for', true);
+ this.fset('to', false);
break;
case 'then':
- this.seenFor = this.wantBy = false;
+ this.fset('for', false);
+ this.fset('to', false);
break;
case 'catch':
case 'function':
@@ -149,10 +151,10 @@ exports.doID = function(code, index){
break;
case 'in':
case 'of':
- if (this.seenFor) {
- this.seenFor = false;
+ if (this.fget('for')) {
+ this.fset('for', false);
if (id === 'of') {
- this.wantBy = true;
+ this.fset('by', true);
id = '';
if (last[0] === 'ID' && ((ref1$ = (ref2$ = this.tokens)[ref2$.length - 2][0]) === ',' || ref1$ === ']' || ref1$ === '}')) {
id = this.tokens.pop()[1];
@@ -238,9 +240,9 @@ exports.doID = function(code, index){
case 'to':
case 'til':
this.forange() && this.tokens.push(['FROM', '', this.line], ['STRNUM', '0', this.line]);
- if (this.seenFrom) {
- this.seenFrom = false;
- this.wantBy = true;
+ if (this.fget('from')) {
+ this.fset('from', false);
+ this.fset('by', true);
tag = 'TO';
} else if (last[0] === 'STRNUM' && !last.callable) {
last[0] = 'RANGE';
@@ -251,13 +253,14 @@ exports.doID = function(code, index){
case 'by':
if (last[0] === 'STRNUM' && (ref5$ = this.tokens)[ref5$.length - 2][0] === 'RANGE') {
tag = 'RANGE_BY';
- } else {
- this.wantBy && (this.wantBy = !(tag = 'BY'));
+ } else if (this.fget('by')) {
+ tag = 'BY';
+ this.fset('by', false);
}
break;
case 'ever':
if (last[0] === 'FOR') {
- this.seenFor = false;
+ this.fset('for', false);
last[0] = 'WHILE';
tag = 'LITERAL';
id = 'true';
@@ -268,6 +271,10 @@ exports.doID = function(code, index){
if (tag === 'RELATION' || tag === 'THEN' || tag === 'ELSE' || tag === 'CASE' || tag === 'DEFAULT' || tag === 'CATCH' || tag === 'FINALLY' || tag === 'IN' || tag === 'OF' || tag === 'FROM' || tag === 'TO' || tag === 'BY' || tag === 'EXTENDS' || tag === 'IMPLEMENTS') {
this.unline();
}
+ if (tag === 'THEN' || tag === 'IF' || tag === 'WHILE') {
+ this.fset('for', false);
+ this.fset('by', false);
+ }
this.token(tag, id);
return input.length;
};
@@ -466,7 +473,8 @@ exports.doLine = function(code, index){
this.newline();
}
}
- this.seenFor = this.wantBy = false;
+ this.fset('for', false);
+ this.fset('by', false);
return length;
};
exports.doSpace = function(code, lastIndex){
@@ -511,8 +519,8 @@ exports.doLiteral = function(code, index){
tag = 'IMPORT';
break;
case ';':
+ this.fset('by', false);
tag = 'NEWLINE';
- this.wantBy = false;
break;
case '.':
if (this.last[1] === '?') {
@@ -692,7 +700,7 @@ exports.doLiteral = function(code, index){
break;
case '=>':
this.unline();
- this.seenFor = false;
+ this.fset('for', false);
if (that = this.doInlinedent(code, index + 2)) {
return 1 + that;
}
@@ -945,8 +953,11 @@ exports.countLines = function(it){
exports.forange = function(){
var ref$, ref1$, ref2$;
if (((ref$ = (ref1$ = this.tokens)[ref1$.length - 2 - ((ref2$ = this.last[0]) === 'NEWLINE' || ref2$ === 'INDENT')]) != null ? ref$[0] : void 8) === 'FOR') {
- return this.seenFor = false, this.seenFrom = true, this;
+ this.fset('for', false);
+ this.fset('from', true);
+ return true;
}
+ return false;
};
exports.validate = function(flag){
var that;
@@ -955,6 +966,14 @@ exports.validate = function(flag){
}
return flag;
};
+exports.fget = function(key){
+ var ref$;
+ return (ref$ = this.flags[this.closes.length]) != null ? ref$[key] : void 8;
+};
+exports.fset = function(key, val){
+ var ref$, key$;
+ return ((ref$ = this.flags)[key$ = this.closes.length] || (ref$[key$] = {}))[key] = val;
+};
exports.carp = function(it){
carp(it, this.line);
};
View
54 src/lexer.co
@@ -52,6 +52,8 @@ exports import
@closes = []
# The stack for tagging parameters.
@parens = []
+ # The stack of flags per nesting level.
+ @flags = []
# Call tokenizers based on the character at current `i`ndex.
# Each tokenizing method is responsible for
# returning the number of characters it has consumed.
@@ -105,14 +107,19 @@ exports import
case \return \throw then tag = \HURL
case \break \continue then tag = \JUMP
case \this \eval \super then return @token(\LITERAL id, true)length
- case \for then @seenFor = true; @wantBy = false; id = []
- case \then then @seenFor = @wantBy = false
+ case \for
+ id = []
+ @fset \for true
+ @fset \to false
+ case \then
+ @fset \for false
+ @fset \to false
case \catch \function then id = ''
case \in \of
- if @seenFor
- @seenFor = false
+ if @fget \for
+ @fset \for false
if id is \of
- @wantBy = true
+ @fset \by true
# OF holds the index variable.
id = ''
if last.0 is \ID and @tokens[*-2]0 of <[ , ] } ]>
@@ -161,21 +168,28 @@ exports import
case \from then @forange! and tag = \FROM
case \to \til
@forange! and @tokens.push [\FROM '' @line] [\STRNUM \0 @line]
- if @seenFrom
- import {-seenFrom, +wantBy}
+ if @fget \from
+ @fset \from false
+ @fset \by true
tag = \TO
else if last.0 is \STRNUM and not last.callable
last <<< 0:\RANGE op:id
return id.length
case \by
if last.0 is \STRNUM and @tokens[*-2]0 is \RANGE
- then tag = \RANGE_BY
- else @wantBy &&= !tag = \BY
+ tag = \RANGE_BY
+ else if @fget \by
+ tag = \BY
+ @fset \by false
case \ever then if last.0 is \FOR
- @seenFor = false; last.0 = \WHILE; tag = \LITERAL; id = \true
+ @fset \for false
+ last.0 = \WHILE; tag = \LITERAL; id = \true
tag ||= match.1.toUpperCase!
@unline! if tag of <[ RELATION THEN ELSE CASE DEFAULT CATCH FINALLY
IN OF FROM TO BY EXTENDS IMPLEMENTS ]>
+ if tag of <[ THEN IF WHILE ]>
+ @fset \for false
+ @fset \by false
@token tag, id
input.length
@@ -335,7 +349,8 @@ exports import
IN OF TO BY FROM EXTENDS IMPLEMENTS ]>
return length
if delta then @indent delta else @newline!
- @seenFor = @wantBy = false
+ @fset \for false
+ @fset \by false
length
# Consumes non-newline whitespaces and/or a line comment.
@@ -358,7 +373,9 @@ exports import
case \/ \% \** then tag = \MATH
case \++ \-- then tag = \CREMENT
case \<<< \<<<< then tag = \IMPORT
- case \; then tag = \NEWLINE; @wantBy = false
+ case \;
+ @fset \by false
+ tag = \NEWLINE
case \.
@last.0 = \? if @last.1 is \?
tag = \DOT
@@ -448,7 +465,7 @@ exports import
case \.. then @adi!; tag = \ID; val = up || \constructor
case \=>
@unline!
- @seenFor = false
+ @fset \for false
return 1 + that if @doInlinedent code, index+2
tag = \THEN
default if \< is val.charAt 0
@@ -641,7 +658,10 @@ exports import
# Checks FOR for FROM/TO.
forange: ->
if @tokens[* - 2 - (@last.0 of <[NEWLINE INDENT]>)]?0 is \FOR
- import {-seenFor, +seenFrom}
+ @fset \for false
+ @fset \from true
+ return true
+ false
# Complains on bad regex flag.
validate: (flag) ->
@@ -649,6 +669,12 @@ exports import
@carp "duplicate regex flag `#{that.1}`"
flag
+ # {G,S}ets a per-nest flag.
+ fget: (key) ->
+ @flags[@closes.length]?[key]
+ fset: (key, val) ->
+ @flags@[@closes.length][key] = val
+
# Throws a syntax error with the current line number.
carp: !-> carp it, @line
View
15 test/loop.co
@@ -71,17 +71,19 @@ eq '036', (i for i from 0 til 9 by 3).join ''
eq '0,-1,-2' ''+for i til -3 then i
-# all/from/to/by aren't reserved off-context.
-all = from = to = by = 1
+# Never mess with binary `in`/`of` and variable `by`/`ever`/`from`/`til`/`to`.
+by = ever = from = til = to = 1
+
+ever for to to to if by for til til til while not by
+
+break for ever from in til of to
-# Never mess with binary `in`/`of` and variable `by`.
for i to 0
ok 0 in [0]
ok 0 of [0]
- ok by = true
+ ok by
by for by of [1]; ok by
-by for by til 1
ok by
@@ -346,7 +348,8 @@ eq \2718,
.join ''
# [#195](https://github.com/satyr/coco/issues/195)
-for [0]
+# [#200](https://github.com/satyr/coco/issues/200)
+for [{} in {} of [[] []]]
ok 0 in {0}
for [1] then ok 1 of [1]
for [2] => ok 2 of [2]
Please sign in to comment.
Something went wrong with that request. Please try again.