@@ -388,13 +388,20 @@ func (p *Parser) parseColumnDeclaration(context util.Path, path util.Path, compu
388388 e sexp.SExp ) (* ast.DefColumn , * SyntaxError ) {
389389 //
390390 var (
391- error * SyntaxError
392- name util.Path
393- multiplier uint = 1
394- datatype ast.Type
395- mustProve bool
396- display string
391+ error * SyntaxError
392+ // Initial binding with defaults
393+ binding = ast.ColumnBinding {
394+ ColumnContext : context ,
395+ Kind : ast .NOT_COMPUTED ,
396+ Multiplier : 1 ,
397+ MustProve : false ,
398+ Display : "hex" ,
399+ }
397400 )
401+ // Update computed status
402+ if computed {
403+ binding .Kind = ast .COMPUTED
404+ }
398405 // Check whether extended declaration or not.
399406 if l := e .AsList (); l != nil {
400407 // Check at least the name provided.
@@ -404,43 +411,40 @@ func (p *Parser) parseColumnDeclaration(context util.Path, path util.Path, compu
404411 return nil , p .translator .SyntaxError (l .Elements [0 ], "invalid column name" )
405412 }
406413 // Column name is always first
407- name = * path .Extend (l .Elements [0 ].String (false ))
414+ binding . Path = * path .Extend (l .Elements [0 ].String (false ))
408415 // Parse type (if applicable)
409- if datatype , mustProve , display , error = p .parseColumnDeclarationAttributes (e , l .Elements [1 :]); error != nil {
416+ if binding , error = p .parseColumnDeclarationAttributes (e , binding , l .Elements [1 :]); error != nil {
410417 return nil , error
411418 }
412419 } else if computed {
413420 // Only computed columns can be given without attributes.
414- name = * path .Extend (e .String (false ))
421+ binding . Path = * path .Extend (e .String (false ))
415422 } else {
416423 return nil , p .translator .SyntaxError (e , "column is untyped" )
417424 }
418425 // Final sanity checks
419- if computed && datatype == nil {
426+ if computed && binding . DataType == nil {
420427 // computed columns initially have multiplier 0 in order to signal that
421428 // this needs to be subsequently determined from context.
422- multiplier = 0
423- datatype = ast .INT_TYPE
424- } else if ! datatype .HasUnderlying () {
429+ binding . Multiplier = 0
430+ binding . DataType = ast .INT_TYPE
431+ } else if ! binding . DataType .HasUnderlying () {
425432 return nil , p .translator .SyntaxError (e , "invalid column type" )
426433 }
427434 //
428- def := ast .NewDefColumn (context , name , datatype , mustProve , multiplier , computed , display )
435+ def := ast .NewDefColumn (binding )
429436 // Update source mapping
430437 p .mapSourceNode (e , def )
431438 //
432439 return def , nil
433440}
434441
435- func (p * Parser ) parseColumnDeclarationAttributes (node sexp.SExp , attrs []sexp. SExp ) ( ast.Type , bool , string ,
436- * SyntaxError ) {
442+ func (p * Parser ) parseColumnDeclarationAttributes (node sexp.SExp , binding ast.ColumnBinding ,
443+ attrs []sexp. SExp ) (ast. ColumnBinding , * SyntaxError ) {
437444 //
438445 var (
439- dataType ast.Type
440- mustProve bool = false
441446 array_min uint
442447 array_max uint
443- display string = "hex"
444448 err * SyntaxError
445449 )
446450
@@ -449,49 +453,67 @@ func (p *Parser) parseColumnDeclarationAttributes(node sexp.SExp, attrs []sexp.S
449453 symbol := ith .AsSymbol ()
450454 // Sanity check
451455 if symbol == nil {
452- return nil , false , "" , p .translator .SyntaxError (ith , "unknown column attribute" )
456+ return binding , p .translator .SyntaxError (ith , "unknown column attribute" )
453457 }
454458 //
455459 switch symbol .Value {
456460 case ":display" :
457461 // skip these for now, as they are only relevant to the inspector.
458462 if i + 1 == len (attrs ) {
459- return nil , false , "" , p .translator .SyntaxError (ith , "incomplete display definition" )
463+ return binding , p .translator .SyntaxError (ith , "incomplete display definition" )
460464 } else if attrs [i + 1 ].AsSymbol () == nil {
461- return nil , false , "" , p .translator .SyntaxError (ith , "malformed display definition" )
465+ return binding , p .translator .SyntaxError (ith , "malformed display definition" )
462466 }
463467 //
464- display = attrs [i + 1 ].AsSymbol ().String (false )
468+ binding . Display = attrs [i + 1 ].AsSymbol ().String (false )
465469 // Check what display attribute we have
466- switch display {
470+ switch binding . Display {
467471 case ":dec" , ":hex" , ":bytes" , ":opcode" :
468- display = display [1 :]
472+ binding . Display = binding . Display [1 :]
469473 // all good
470474 i = i + 1
471475 default :
472476 // not good
473- return nil , false , "" , p .translator .SyntaxError (ith , "unknown display definition" )
477+ return binding , p .translator .SyntaxError (ith , "unknown display definition" )
474478 }
475479 case ":array" :
476480 if array_min , array_max , err = p .parseArrayDimension (attrs [i + 1 ]); err != nil {
477- return nil , false , "" , err
481+ return binding , err
478482 }
479483 // skip dimension
480484 i ++
485+ case ":fwd" :
486+ switch binding .Kind {
487+ case ast .NOT_COMPUTED :
488+ return binding , p .translator .SyntaxError (ith , "input columns cannot be recursive" )
489+ case ast .COMPUTED_BWD :
490+ return binding , p .translator .SyntaxError (ith , "conflicting direction of recursion" )
491+ default :
492+ binding .Kind = ast .COMPUTED_FWD
493+ }
494+ case ":bwd" :
495+ switch binding .Kind {
496+ case ast .NOT_COMPUTED :
497+ return binding , p .translator .SyntaxError (ith , "input columns cannot be recursive" )
498+ case ast .COMPUTED_FWD :
499+ return binding , p .translator .SyntaxError (ith , "conflicting direction of recursion" )
500+ default :
501+ binding .Kind = ast .COMPUTED_BWD
502+ }
481503 default :
482- if dataType , mustProve , err = p .parseType (ith ); err != nil {
483- return nil , false , "" , err
504+ if binding . DataType , binding . MustProve , err = p .parseType (ith ); err != nil {
505+ return binding , err
484506 }
485507 }
486508 }
487509 // Done
488- if dataType == nil {
489- return nil , false , "" , p .translator .SyntaxError (node , "column is untyped" )
510+ if binding . DataType == nil {
511+ return binding , p .translator .SyntaxError (node , "column is untyped" )
490512 } else if array_max != 0 {
491- return ast .NewArrayType (dataType , array_min , array_max ), mustProve , display , nil
513+ binding . DataType = ast .NewArrayType (binding . DataType , array_min , array_max )
492514 }
493- //
494- return dataType , mustProve , display , nil
515+ // Success!
516+ return binding , nil
495517}
496518
497519func (p * Parser ) parseArrayDimension (s sexp.SExp ) (uint , uint , * SyntaxError ) {
0 commit comments