1
votes

I'm new here but I hope someone can help me. I'm developing a Prolog-like DSL for an university project. This is a simplified grammar that I use to expertiment stuff:

grammar it.unibo.gciatto.Garbage hidden (SL_COMMENT, ML_COMMENT, WS, ANY_OTHER)

import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate garbage "http://www.unibo.it/gciatto/Garbage"

PTheory returns Theory
    :   (kb+=PExpression '.')*
    ;

PExpression returns Expression
    :   PRule
    ;

PRule returns Expression
    :   PConjunction ({ Expression.left=current } name=':-' right=PConjunction)?
    ;

PConjunction returns Expression
    :   PExpression0 ({ Expression.left=current } name=',' right=PConjunction)?
    ;

PExpression0 returns Expression
    :   PTerm
    |   '(' PExpression ')'
    ;

PTerm returns Term
    :   PStruct
    |   PVariable
    |   PNumber
    ;

PVariable returns Variable
    :   { AnonymousVariable } name='_'
    |   name=VARIABLE
    ;

PNumber returns Number
    :   value=INT
    ;

PStruct returns Struct
    :   name=ATOM '(' arg+=PExpression0 (',' arg+=PExpression0)* ')'
    |   PAtom
    ;

PAtom returns Atom
    :   name=ATOM
    |   { AtomString } name=STRING
    ;


terminal fragment CHARSEQ : ('a'..'z' | 'A' .. 'Z' | '0'..'9' | '_')*;
terminal ATOM : ('a'..'z') CHARSEQ;
terminal VARIABLE : ('A'..'Z') CHARSEQ;
terminal INT returns ecore::EInt: ('0'..'9')+;
terminal STRING : 
            '"' ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|'"') )* '"' |
            "'" ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|"'") )* "'"
        ; 
terminal ML_COMMENT : '/*' -> '*/';
terminal SL_COMMENT     : '//' !('\n'|'\r')* ('\r'? '\n')?;

terminal WS         : (' '|'\t'|'\r'|'\n')+;

terminal ANY_OTHER: .;

When validating I'd love to search for unused variables in rules definition and suggest the user to use anonymous variable instead. Once I've understood the mechanism I may consider similar validation rules. I know Xtext has a built-in scoping mechanism and I've been able to use it in different situations, but as you know, any IScopeProvider provides a scope for a given EReference (am I right?) and, as you can see, my grammar has no cross-references. The reason for that is simple: in Prolog a variable "definition" and its "references" are syntactically the same, so no context-free parser able to distinguish the two contexts can be generated (I'm pretty sure, even without a formal proof). However, I think the validation algorithm is quite simple:

"while navigating the AST, collect any variable within an ad-hoc data structure and the count occurrences" or something smarter than that

Now the real question is: can I someway (re)use any part of the Xtext scoping framework, and if yes how? Or should I build a simple scoping library by my self?

Sorry for the long question and bad english, I hope I was exhaustive. Thank you for reading.

2
using Definite Clause Grammars (DCG) in SWI-Prolog may be useful about your question, - Ans Piter
Thank you for your answer but that's not an option: I need to create an Eclipse plug-in for a Prolog-LIKE language which does not support DCGs. - Giovanni Ciatto
Is your language Prolog-like enough so that it is actually valid Prolog code (possibly if suitable operators are defined)? If so, then a simple way to detect singletons suggests itself: Invoke a Prolog interpreter, consult the file, and see if it generates any singleton warnings. Fetch the warnings and present them to you users. Also +1 for the DCG suggestion by Ans Piter: Obviously what Ans meant is to create a DCG that parses your language, and then apply your reasoning, invoking Prolog from Eclipse to do it. It is not important whether your language itself supports DCGs for that! - mat
Sadly the Prolog engine I have to use, doesn't throw singleton warnings - Giovanni Ciatto

2 Answers

0
votes

The Xtext validation framework can reuse your scope provider instance easily, and can write validation rules. A sample for the validator is already generated for the Xtext grammar, you have to extend it with your specific validation case like follows:

public class GarbageLanguageJavaValidator extends AbstractGarbageLanguageJavaValidator {

  @Inject
  GarbageLanguageScopeProvider scopeProvider;


  //Validation rule for theories. For any other element, change the input parameter
  @Check
  public void checkTheory(Theory theory) {
    //here, you can simply reuse the injected scope provider
    scopeProvider.getAllReferencesInTheory();
    //in case of problems, report errors using the inherited error/warning methods
  }

}

The created validation rules are automatically registered and executed (see also the Xtext documentation for details about validation).

0
votes

I actually solved the problem a few days after I posted the question and then I was too busy to post the solution. Here it comes (for a more detailed description of both the problem and the solution, you are free to read the essay I wrote: RespectX - section 4.5 ).

  • I created my own IQualifiedNameProvider, called IPrologSimpleNameProvider, which simply returns the 'name' feature.
  • Then I created my own IContextualScopeProvider, which doesn't extend IScopeProvider. It exposes the following methods:
    • getContext given any AST node, it returns the root of the current context, i.e. the EObject whose eContainer is instance of Theory and containing the input node within its sub-tree.
    • getScope returns an IScope for the context of the input node.
    • getFilteredScope applies a type-filter to a getScope invocation (e.g. it makes it easy to create a scope containing only Variables).
    • getFilteredScope filters a getScope invocation using a predicate.

Of course, the IContextualScopeProvider implementation uses an IPrologSimpleNameProvider implementation so, now, the validation rule quite simple to realize:

  1. Given a variable, it uses the getScope method which returns an IScope containing all the variables within that context
  2. It counts how many variables within the IScope are named after the current one
  3. If they are lesser than 2 a warning is found.

I really hope I explained ^^"