Skip to content

Commit

Permalink
testing the validity of produced asts
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabien committed Dec 31, 2010
1 parent fbc5ecf commit 3790f5c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 22 deletions.
40 changes: 28 additions & 12 deletions src/CoffeeScriptParser.coffee
Expand Up @@ -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]
Expand All @@ -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
Expand Down Expand Up @@ -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) ->
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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) ->
Expand All @@ -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)

Expand Down
37 changes: 33 additions & 4 deletions test/test_cs.coffee
@@ -1,6 +1,13 @@
Array.prototype.toString = -> '[ ' + (@join ', ') + ' ]'
Function.prototype.toString = -> "<FUNCTION>"

# 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 = -> "<FUNCTION>"

# Enable this to print objects content.
if false
Object.prototype.toString = ->
'{' + (("#{k}: #{v}" for k, v of @).join ', ') + '}'
Expand All @@ -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"

Expand All @@ -38,6 +55,7 @@ src.lambda1 = """
-> meh
(x) -> (y) -> curry
"""

ast.lambda1 = [
tree 'Function', [tree 'Id', 'x'], [tree 'Id', 'x']
tree 'Function',
Expand Down Expand Up @@ -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 = """
Expand Down Expand Up @@ -222,6 +240,14 @@ src.object3 = '''
d:2 } } }
'''

src.object4 = '''
{
a:
b:
c:1
d:2 }
'''

src.operators = """
a + b * c
d ? e ? f
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
12 changes: 6 additions & 6 deletions test/test_keys.coffee
Expand Up @@ -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'

Expand Down

0 comments on commit 3790f5c

Please sign in to comment.