From 3790f5c3abc0ec97c85683724092f1e7ea5d3035 Mon Sep 17 00:00:00 2001 From: Fabien Date: Fri, 31 Dec 2010 10:16:44 +0100 Subject: [PATCH] testing the validity of produced asts --- src/CoffeeScriptParser.coffee | 40 ++++++++++++++++++++++++----------- test/test_cs.coffee | 37 ++++++++++++++++++++++++++++---- test/test_keys.coffee | 12 +++++------ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/CoffeeScriptParser.coffee b/src/CoffeeScriptParser.coffee index a20550b..8bf011f 100644 --- a/src/CoffeeScriptParser.coffee +++ b/src/CoffeeScriptParser.coffee @@ -42,9 +42,9 @@ cs.return = gg.sequence("return", gg.maybe cs.expr).setBuilder (x) -> # try ... catch ... finally cs.try = gg.sequence( - "try", cs.block, - gg.if('catch', gg.sequence(gg.id, cs.lineOrBlock)), - gg.if('finally', cs.block) #lineorbblock? + "try", cs.lineOrBlock, + gg.maybe('catch', gg.sequence(gg.id, cs.lineOrBlock)).setBuilder(1), + gg.maybe('finally', cs.lineOrBlock).setBuilder(1) ).setBuilder (x) -> tblock = x[1] [_, cid, cblock] = x[2] if x[2] @@ -58,7 +58,7 @@ cs.whileLine = gg.sequence( gg.if('when', cs.expr) ).setBuilder (x) -> { cond, invert, guard } = x - if invert then cond = tree "!", cond + if invert then cond = tree 'Op', '!', cond return tree [cond, guard] # block-prefix while/until statement @@ -88,8 +88,12 @@ cs.forLine = gg.sequence( ).setBuilder (x) -> [ _, own, vars, op, collection, { guard, step} ] = x return gg.fail if op=='of' and step + return gg.fail if op=='in' and own return gg.fail unless 1 <= vars.length <= 2 - return [ op, vars, collection, guard, step ] + r = [ op, vars, collection ] + r.push guard if guard or step + r.push step if step + return r # block-prefix for statement cs.for = gg.sequence(cs.forLine, cs.block).setBuilder (x) -> @@ -193,7 +197,7 @@ cs.parentheses = gg.sequence( if param.tag=='Id' continue else if param.tag=='Op' and param.children[0]=='...' and param.children[1].tag=='Id' - if splatIdx then return gg.fail # multiple splats + if splatIdx then return gg.fail # multiple splats forbidden else splatIdx = i; insideParens[i]=param.children[1] else return gg.fail # invalid parameter @@ -259,7 +263,8 @@ class MultiLine extends gg.Parser reindex: -> @seq.reindex() - @keys = @seq.keys + @catcodes = @seq.catcodes + @epsilon = @seq.epsilon return super parse: (lx) -> @@ -283,12 +288,23 @@ cs.array = cs.multiLine { suffix: ']' } .setBuilder (x) -> tree 'Array', x -cs.object = cs.multiLine { - prefix: '{' - primary: gg.sequence(gg.id, ':', cs.expr).setBuilder (x) -> [x[0], x[2]] +cs.objectEntry = + gg.sequence(gg.id, ':', cs.expr).setBuilder (x) -> [x[0], x[2]] + +cs.objectWithoutBraces = cs.multiLine({ + primary: cs.objectEntry + separator: gg.choice(',', ';', gg.one) +}).setBuilder (x) -> tree 'Object', x + +cs.objectWithBraces = cs.multiLine({ + prefix: "{" + primary: cs.objectEntry separator: gg.choice(',', ';', gg.one) - suffix: '}' } -.setBuilder (x) -> tree 'Object', x + suffix: "}" +}).setBuilder (x) -> tree 'Object', x + +cs.object = gg.choice(cs.objectWithoutBraces, cs.objectWithBraces) +#cs.object = cs.objectWithBraces cs.string = gg.wrap(gg.string).setBuilder((x) -> tree 'String', x) diff --git a/test/test_cs.coffee b/test/test_cs.coffee index 27d33cf..6455caf 100644 --- a/test/test_cs.coffee +++ b/test/test_cs.coffee @@ -1,6 +1,13 @@ -Array.prototype.toString = -> '[ ' + (@join ', ') + ' ]' -Function.prototype.toString = -> "" +# Enable this to print array elements. +if true + Array.prototype.toString = -> '[ ' + (@join ', ') + ' ]' + +# Enable this to prevent function printing from dumping whole sources +if true + Function.prototype.toString = -> "" + +# Enable this to print objects content. if false Object.prototype.toString = -> '{' + (("#{k}: #{v}" for k, v of @).join ', ') + '}' @@ -9,9 +16,19 @@ cs = require "../src/CoffeeScriptParser" gg = require "../src/GrammarGenerator" { tree, toIndentedString, equal:astEqual } = require '../src/Tree' +# set of source strings, indexed by names, to be run as tests. +# Each string must be a valid coffeescript block, unless its +# name starts with "fail_": in this case it must *not* parse +# correctly. src = { } + +# set of expected ASTs, indexed by names. An AST is optional +# in a test, but if there is one, then the result of the parser +# must match. ast = { } +#--- TESTS --------------------------------------------------------------------- + # basic identifier src.id = "foo" @@ -38,6 +55,7 @@ src.lambda1 = """ -> meh (x) -> (y) -> curry """ + ast.lambda1 = [ tree 'Function', [tree 'Id', 'x'], [tree 'Id', 'x'] tree 'Function', @@ -86,7 +104,7 @@ ast.lambda3 = [ (tree 'Id', 'last'), (tree 'Function', [(tree 'Id', 'a'), (tree 'Id', 'b')], [tree 'Id', 'b'], 0))] -src.fail_lambda1 = '(a, b..., c...) -> "at most one splatted arg"' +src.fail_lambda1 = '(a, b..., c...) -> "no more than one splatted arg"' # super invocations src.super = """ @@ -222,6 +240,14 @@ src.object3 = ''' d:2 } } } ''' +src.object4 = ''' +{ + a: + b: + c:1 + d:2 } +''' + src.operators = """ a + b * c d ? e ? f @@ -285,6 +311,9 @@ ast.cmp2 = [ (tree 'Id', 'z')) ] +#--- END OF TESTS -------------------------------------------------------------- + + # Determine the set of test names to run # src: test suite # regexes: list of regexes, presumably passed from command line @@ -301,7 +330,7 @@ getTestsToRun = (src, regexes) -> used_regexes[regex] = true break for regex in regexes - unless used_regex[regex] + unless used_regexes[regex] print "Warning, unused regex '#{regex}'\n" return tests diff --git a/test/test_keys.coffee b/test/test_keys.coffee index 7a09944..0bd555a 100644 --- a/test/test_keys.coffee +++ b/test/test_keys.coffee @@ -20,23 +20,23 @@ print "\n\n--- Keys dump ---\n" for name, parser of cs continue unless parser instanceof gg.Parser - if parser.keys - print "cs.#{name}\t--has-keys-->\t#{kwlist parser.keys}\n" + if parser.catcodes + print "cs.#{name}\t--has-catcodes-->\t#{if parser.epsilon then 'epsilon + ' else ''}#{kwlist parser.catcodes}\n" if parser instanceof gg.Expr if parser.primary - print "\t expr primary keys: #{kwlist parser.primary.keys}\n" + print "\t expr primary keys: #{kwlist parser.primary.catcodes}\n" else print "\t no primary parser\n" for setname in ['prefix', 'infix', 'suffix'] set = parser[setname] - print "\t expr #{setname} keys: #{kwlist set}\n" + print "\t expr #{setname} catcodes: #{kwlist set}\n" else print "cs.#{name} has no key\n" print '\n' for name, parser of cs - unless parser not instanceof gg.Parser or parser.keys - print "(cs.#{name}: no keys)\n" + unless parser not instanceof gg.Parser or parser.catcodes + print "(cs.#{name}: no catcode)\n" print '\n'