PageRenderTime 25ms CodeModel.GetById 15ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/ooc/frontend/parser/FunctionDeclParser.java

http://github.com/nddrylliog/ooc
Java | 142 lines | 121 code | 20 blank | 1 comment | 39 complexity | 13c7bf94f3f372defbd72db03853c92f MD5 | raw file
  1package org.ooc.frontend.parser;
  2
  3import java.util.ArrayList;
  4import java.util.List;
  5
  6import org.ooc.frontend.model.FunctionDecl;
  7import org.ooc.frontend.model.Module;
  8import org.ooc.frontend.model.OocDocComment;
  9import org.ooc.frontend.model.Type;
 10import org.ooc.frontend.model.TypeParam;
 11import org.ooc.frontend.model.tokens.Token;
 12import org.ooc.frontend.model.tokens.TokenReader;
 13import org.ooc.frontend.model.tokens.Token.TokenType;
 14import org.ubi.CompilationFailedError;
 15import org.ubi.SourceReader;
 16
 17public class FunctionDeclParser {
 18
 19	public static FunctionDecl parse(Module module, SourceReader sReader, TokenReader reader, boolean skipFunc) {
 20		int mark = reader.mark();
 21		
 22		OocDocComment comment = null;
 23		if(reader.peek().type == TokenType.OOCDOC) {
 24			Token token = reader.read();
 25			comment = new OocDocComment(token.get(sReader), token);
 26			// allow an arbitrary number of newlines after the oocdoc comment.
 27			while(reader.peek().type == TokenType.LINESEP)
 28				reader.skip();
 29		}
 30		
 31		Token startToken= reader.peek();
 32		
 33		String name = "";
 34		Token tName = reader.peek();
 35		if(tName.isNameToken()) {
 36			name = tName.get(sReader);
 37			reader.skip();
 38			if(reader.read().type != TokenType.COLON) {
 39				reader.reset(mark);
 40				return null;
 41			}
 42		}
 43		
 44		boolean isProto = false;
 45		boolean isAbstract = false;
 46		boolean isStatic = false;
 47		boolean isFinal = false;
 48		boolean isInline = false;
 49		String externName = null;
 50		String unmangledName = null;
 51		
 52		Token kw = reader.peek();
 53		keywordRead: while(true) {
 54			switch(kw.type) {
 55			case TokenType.ABSTRACT_KW: reader.skip(); isAbstract = true; break;
 56			case TokenType.STATIC_KW: reader.skip(); isStatic = true; break;
 57			case TokenType.FINAL_KW: reader.skip(); isFinal = true; break;
 58			case TokenType.PROTO_KW: reader.skip(); isProto = true; break;
 59			case TokenType.INLINE_KW: reader.skip(); isInline = true; break;
 60			case TokenType.EXTERN_KW: externName = ExternParser.parse(sReader, reader); break;
 61			case TokenType.UNMANGLED_KW: unmangledName = UnmangledParser.parse(sReader, reader); break;
 62			default: break keywordRead;
 63			}
 64			kw = reader.peek();
 65		}
 66		
 67		if(reader.peek().type == TokenType.FUNC_KW) {
 68			reader.skip();
 69		} else if(!skipFunc) {
 70			reader.reset(mark);
 71			return null;
 72		}
 73		
 74		String suffix = "";
 75		List<TypeParam> genTypes = null;
 76		while(true) {
 77			Token tok = reader.peek();
 78			if(tok.type == TokenType.TILDE) {
 79				reader.skip();
 80				Token tSuffix = reader.peek();
 81				if(tSuffix.isNameToken()) {
 82					reader.skip();
 83					suffix = tSuffix.get(sReader);
 84				}
 85			} else if(tok.type == TokenType.LESSTHAN) {
 86				reader.skip();
 87				genTypes = new ArrayList<TypeParam>();
 88				TypeParamParser.parse(sReader, reader, genTypes);
 89			} else break;
 90		}
 91		
 92		FunctionDecl functionDecl = new FunctionDecl(
 93				name, suffix, isFinal, isStatic, isAbstract, externName, startToken, module);
 94		functionDecl.setInline(isInline);
 95		functionDecl.setUnmangledName(unmangledName);
 96		functionDecl.setProto(isProto);
 97		if(genTypes != null) {
 98			for(TypeParam genType: genTypes) {
 99				functionDecl.getTypeParams().put(genType.getName(), genType);
100			}
101		}
102		if(comment != null) functionDecl.setComment(comment);
103		
104		ArgumentParser.fill(module, sReader, reader, functionDecl.isExtern(), functionDecl.getArguments());
105		
106		Token token = reader.peek();
107		if(token.type == TokenType.ARROW) {
108			reader.skip();
109			reader.skipWhitespace();
110			Type returnType = TypeParser.parse(module, sReader, reader, false);
111			if(returnType == null) {
112				throw new CompilationFailedError(sReader.getLocation(reader.peek()),
113						"Expected return type after '->'");
114			}
115			functionDecl.setReturnType(returnType);
116		}
117		
118		if(externName != null || isAbstract) {
119			return functionDecl;
120		}
121
122		token = reader.readWhiteless();
123		if(token == null || token.type != TokenType.OPEN_BRACK) {
124			throw new CompilationFailedError(sReader.getLocation(reader.prev(2)),
125					"Expected body, e.g. {} after a function name (even for empty functions)");
126		}
127	
128		while(reader.hasNext() && reader.peek().type != TokenType.CLOS_BRACK) {
129			reader.skipWhitespace();
130		
131			if(!LineParser.fill(module, sReader, reader, functionDecl.getBody()) && reader.hasNext()
132					&& reader.peek().type != TokenType.CLOS_BRACK) {
133				throw new CompilationFailedError(sReader.getLocation(reader.peek()),
134						"Expected statement in function body. Found "+reader.peek()+" instead.");
135			}
136		}
137		reader.skip();
138		
139		return functionDecl;
140	}
141	
142}