package org.fandev.lang.fan.parsing.topLevel;
import com.intellij.lang.PsiBuilder;
import static org.fandev.lang.fan.FanBundle.message;
import static org.fandev.lang.fan.FanElementTypes.*;
import static org.fandev.lang.fan.FanTokenTypes.*;
import org.fandev.lang.fan.parsing.statements.typeDefinitions.typeDefs.TypeDefinition;
import org.fandev.lang.fan.parsing.util.ParserUtils;
import static org.fandev.lang.fan.parsing.util.ParserUtils.getToken;
/**
* <ul>
* <li><compilationUnit> := <using>* <typeDef>* </li>
* <li><using> := <usingPod> | <usingType> | <usingAs></li>
* <li><usingPod> := "using" <podSpec> <eos></li>
* <li><usingType> := "using" <podSpec> "::" <id> <eos></li>
* <li><usingAs> := "using" <podSpec> "::" <id> "as" <id> <eos></li>
* <li><podSpec> := [ffi] <id> ("." <id>)*</li>
* <li><ffi> := "[" <id> "]"</li>
* </ol>
*
* @author Dror Bereznitsky
* @author Fred Simon
* @date Jan 6, 2009 11:25:52 PM
*/
public class CompilationUnit {
public static void parse(final PsiBuilder builder) {
// Shabeng should be the first token of the file
if (SHABENG == builder.getTokenType()) {
final PsiBuilder.Marker shBeng = builder.mark();
if (!ParserUtils.advanceTo(builder, EOL)) {
shBeng.error(message("separator.expected"));
return;
} else {
shBeng.done(SHABENG);
}
}
ParserUtils.removeNls(builder);
while (USING_KEYWORD == builder.getTokenType()) {
parseUsing(builder);
}
while (!builder.eof()) {
if (!TypeDefinition.parse(builder)) {
ParserUtils.cleanAfterErrorInBlock(builder);
}
}
}
private static void parseUsing(final PsiBuilder builder) {
final PsiBuilder.Marker usingStatement = builder.mark();
final PsiBuilder.Marker usingKeyword = builder.mark();
builder.advanceLexer();
usingKeyword.done(USING_KEYWORD);
if (LBRACKET.equals(builder.getTokenType())) {
// A FFI import
builder.advanceLexer();
final PsiBuilder.Marker ffiMark = builder.mark();
if (getToken(builder, IDENTIFIER_TOKENS_SET, message("identifier.expected")))
ffiMark.done(FFI_NAME);
else
ffiMark.drop();
getToken(builder, RBRACKET, message("rbrack.expected"));
}
// A list of id with dots :)
final PsiBuilder.Marker podIdExpr = builder.mark();
final PsiBuilder.Marker podRefMark = builder.mark();
do {
getToken(builder, IDENTIFIER_TOKENS_SET, message("identifier.expected"));
} while (getToken(builder, DOT));
podRefMark.done(POD_REFERENCE);
if (getToken(builder, COLON_COLON)) {
final PsiBuilder.Marker usingType = builder.mark();
final PsiBuilder.Marker m = builder.mark();
getToken(builder, IDENTIFIER_TOKENS_SET, message("identifier.expected"));
m.done(NAME_ELEMENT);
usingType.done(ID_EXPR);
}
podIdExpr.done(ID_EXPR);
if (getToken(builder, AS_KEYWORD)) {
final PsiBuilder.Marker m = builder.mark();
getToken(builder, IDENTIFIER_TOKENS_SET, message("identifier.expected"));
m.done(USING_AS_NAME);
}
usingStatement.done(USING_STATEMENT);
if (!EOL.contains(builder.getTokenType())) {
builder.error(message("separator.expected"));
ParserUtils.advanceTo(builder,EOL);
} else {
builder.advanceLexer();
}
ParserUtils.removeNls(builder);
}
}