/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* $Rev$ $Date$ */ #ifndef tuscany_scheme_io_hpp #define tuscany_scheme_io_hpp /** * Script evaluator IO functions. */ #include #include "stream.hpp" #include "string.hpp" #include "list.hpp" #include "value.hpp" #include "primitive.hpp" namespace tuscany { namespace scheme { const value rightParenthesis(mklist(")")); const value leftParenthesis(mklist("(")); const value comment(mklist(";")); const double stringToNumber(const string& str) { return atof(c_str(str)); } const bool isWhitespace(const char ch) { return ch != -1 && isspace(ch); } const bool isIdentifierStart(const char ch) { return ch != -1 && !isspace(ch) && !isdigit(ch); } const bool isIdentifierPart(const char ch) { return ch != -1 && !isspace(ch) && ch != '(' && ch != ')'; } const bool isDigit(const char ch) { return isdigit(ch) || ch == '.'; } const bool isLeftParenthesis(const value& token) { return leftParenthesis == token; } const bool isRightParenthesis(const value& token) { return rightParenthesis == token; } const char readChar(istream& in) { if(in.eof()) { return -1; } char c = (char)get(in); return c; } const char peekChar(istream& in) { if(eof(in)) return -1; char c = (char)peek(in); return c; } const bool isQuote(const value& token) { return token == quoteSymbol; } const failable skipComment(istream& in); const value readQuoted(istream& in); const value readIdentifier(const char chr, istream& in); const value readString(istream& in); const value readNumber(const char chr, istream& in); const value readValue(istream& in); const failable readToken(istream& in) { const char firstChar = readChar(in); if(isWhitespace(firstChar)) return readToken(in); if(firstChar == ';') return skipComment(in); if(firstChar == '\'') return readQuoted(in); if(firstChar == '(') return leftParenthesis; if(firstChar == ')') return rightParenthesis; if(firstChar == '"') return readString(in); if(isIdentifierStart(firstChar)) return readIdentifier(firstChar, in); if(isDigit(firstChar)) return readNumber(firstChar, in); if(firstChar == -1) return mkfailure(); logStream() << "Illegal lexical syntax '" << firstChar << "'" << endl; return readToken(in); } const failable skipComment(istream& in) { const char nextChar = readChar(in); if (nextChar == '\n') return readToken(in); return skipComment(in); } const value readQuoted(istream& in) { return mklist(quoteSymbol, readValue(in)); } const list readList(const list& listSoFar, istream& in) { const failable ftoken = readToken(in); if (!hasContent(ftoken)) return reverse(listSoFar); const value token = content(ftoken); if(isRightParenthesis(token)) return reverse(listSoFar); if(isLeftParenthesis(token)) return readList(cons(value(readList(list (), in)), listSoFar), in); return readList(cons(token, listSoFar), in); } const string listToString(const list& l) { if(isNil(l)) return ""; const char buf[1] = { car(l) }; return string(buf, 1) + listToString(cdr(l)); } const list readIdentifierHelper(const list& listSoFar, istream& in) { const char nextChar = peekChar(in); if(isIdentifierPart(nextChar)) return readIdentifierHelper(cons(readChar(in), listSoFar), in); return reverse(listSoFar); } const value readIdentifier(const char chr, istream& in) { const value val = c_str(listToString(readIdentifierHelper(mklist(chr), in))); if (val == "false") return value((bool)false); if (val == "true") return value((bool)true); if (val == "nil") return value(); return val; } const list readStringHelper(const list& listSoFar, istream& in) { const char nextChar = readChar(in); if(nextChar == -1 || nextChar == '"') return reverse(listSoFar); if (nextChar == '\\') { const char escapedChar = readChar(in); if (escapedChar == -1) return reverse(listSoFar); return readStringHelper(cons(escapedChar, listSoFar), in); } return readStringHelper(cons(nextChar, listSoFar), in); } const value readString(istream& in) { return listToString(readStringHelper(list(), in)); } const list readNumberHelper(const list& listSoFar, istream& in) { const char nextChar = peekChar(in); if(isDigit(nextChar)) return readNumberHelper(cons(readChar(in), listSoFar), in); return reverse(listSoFar); } const value readNumber(const char chr, istream& in) { return stringToNumber(listToString(readNumberHelper(mklist(chr), in))); } const value readValue(istream& in) { const failable fnextToken = readToken(in); if (!hasContent(fnextToken)) return value(); const value nextToken = content(fnextToken); if(isLeftParenthesis(nextToken)) return readList(list(), in); return nextToken; } const value readValue(const string s) { istringstream in(s); const failable fnextToken = readToken(in); if (!hasContent(fnextToken)) return value(); const value nextToken = content(fnextToken); if(isLeftParenthesis(nextToken)) return readList(list(), in); return nextToken; } const bool writeValue(const value& val, ostream& out) { out << val; return true; } const string writeValue(const value& val) { ostringstream out; out << val; return str(out); } const value readScript(istream& in) { const value val = readValue(in); if (isNil(val)) return list(); return cons(val, (list)readScript(in)); } } } #endif /* tuscany_scheme_io_hpp */