Question

I'm currently trying Rascal to create a small DSL. I tried to modify the Pico example, however I'm currently stuck. The following code parses examples like a = 3, b = 7 begin declare x : natural, field real @ cells blubb; x := 5.7 end parses perfectly, but the implode function fails with the error message "Cannot find a constructor for PROGRAM". I tried various constructor declarations, however none seemed to fit. Is there a way to see what the expected constructor looks like?

Syntax:

module BlaTest::Syntax

import Prelude;

lexical Identifier  = [a-z][a-z0-9]* !>> [a-z0-9];
lexical NaturalConstant = [0-9]+;
lexical IntegerConstant = [\-+]? NaturalConstant;
lexical RealConstant = IntegerConstant "." NaturalConstant;
lexical StringConstant = "\"" ![\"]*  "\"";

layout Layout = WhitespaceAndComment* !>> [\ \t\n\r%];

lexical WhitespaceAndComment 
   = [\ \t\n\r]
   | @category="Comment" "%" ![%]+ "%"
   | @category="Comment" "%%" ![\n]* $
   ;

start syntax Program
   = program: {ExaOption ","}* exadomain "begin" Declarations decls {Statement ";"}* body "end"
   ;

syntax Domain = "domain" "{" ExaOption ", " exaoptions "}"
   ;

syntax ExaOption = Identifier id "=" Expression val
   ;

syntax Declarations 
   = "declare" {Declaration ","}* decls ";" ;

syntax Declaration
   = variable_declaration: Identifier id ":" Type tp
   | field_declaration: "field" Type tp "@" FieldLocation fieldLocation Identifier id
   ;

syntax FieldLocation
   = exacell: "cells"
   | exanode: "nodes"
   ;

syntax Type 
   = natural:"natural"
   | exareal: "real"
   | string :"string"
   ;


syntax Statement 
   = asgStat: Identifier var ":=" Expression val 
   | ifElseStat: "if" Expression cond "then" {Statement ";"}* thenPart "else" {Statement ";"}* elsePart "fi"
   | whileStat: "while" Expression cond "do" {Statement ";"}* body "od"
   ;

syntax Expression 
   = id: Identifier name
   | stringConstant: StringConstant stringconstant
   | naturalConstant: NaturalConstant naturalconstant
   | realConstant: RealConstant realconstant
   | bracket "(" Expression e ")"
   > left conc: Expression lhs "||" Expression rhs
   > left ( add: Expression lhs "+" Expression rhs
          | sub: Expression lhs "-" Expression rhs
          )
  ;

public start[Program] program(str s) {
  return parse(#start[Program], s);
}

public start[Program] program(str s, loc l) {
  return parse(#start[Program], s, l);
} 

Abstract:

module BlaTest::Abstract

public data TYPE = natural() | string() | exareal();
public data FIELDLOCATION = exacell() | exanode();

public alias ExaIdentifier = str;

public data PROGRAM = program(list[OPTION] exadomain, list[DECL] decls, list[STATEMENT] stats);


public data DOMAIN
   = domain_declaration(list[OPTION] options)
   ;


public data OPTION
   = exaoption(ExaIdentifier name, EXP exp)
   ;

public data DECL
   = variable_declaration(ExaIdentifier name, TYPE tp)
   | field_declaration(TYPE tp, FIELDLOCATION fieldlocation, ExaIdentifier name)
   ;



public data EXP
   = id(ExaIdentifier name)
   | naturalConstant(int iVal)
   | stringConstant(str sVal)
   | realConstant(real rVal)
   | add(EXP left, EXP right)
   | sub(EXP left, EXP right)
   | conc(EXP left, EXP right)
   ;

public data STATEMENT
   = asgStat(ExaIdentifier name, EXP exp)
   | ifElseStat(EXP exp, list[STATEMENT] thenpart, list[STATEMENT] elsepart)
   | whileStat(EXP exp, list[STATEMENT] body)
   ;

anno loc TYPE@location;
anno loc PROGRAM@location;
anno loc DECL@location;
anno loc EXP@location;
anno loc STATEMENT@location;
anno loc OPTION@location;

public alias Occurrence = tuple[loc location, ExaIdentifier name, STATEMENT stat];

Load:

module BlaTest::Load

import IO;
import Exception;
import Prelude;

import BlaTest::Syntax;
import BlaTest::Abstract;

import BlaTest::ControlFlow;
import BlaTest::Visualize;

public PROGRAM exaload(str txt) {
    PROGRAM p;
    try {
        p = implode(#PROGRAM, parse(#Program, txt));
    } catch ParseError(loc l): {
        println("Parse error at line <l.begin.line>, column <l.begin.column>");
    }
    return p; // return will fail in case of error
}

public Program exaparse(str txt) {
    Program p;
    try {
        p = parse(#Program, txt);
    } catch ParseError(loc l): {
        println("Parse error at line <l.begin.line>, column <l.begin.column>");
    }
    return p; // return will fail in case of error
}

Thanks a lot, Chris

Was it helpful?

Solution

Unfortunately the current implode facility depends on a hidden semantic assumption, namely that the non-terminals in the syntax definition have the same name as the types in the data definitions. So if the non-terminal is called "Program", it should not be called "PROGRAM" but "Program" in the data definition.

We are looking for a smoother way of integrating concrete and abstract syntax trees, but for now please decapitalize your data names.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top