forked from Mirror/wren
Initial commit.
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Output directory.
|
||||
build/
|
||||
|
||||
# XCode user-specific stuff.
|
||||
xcuserdata/
|
||||
1
example/hello.wren
Normal file
1
example/hello.wren
Normal file
@ -0,0 +1 @@
|
||||
123(1, true, "a string".whatevs)
|
||||
233
src/lexer.c
Normal file
233
src/lexer.c
Normal file
@ -0,0 +1,233 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Buffer* source;
|
||||
|
||||
int start; // The beginning of the current token.
|
||||
int pos;
|
||||
|
||||
Token* head;
|
||||
Token* tail;
|
||||
|
||||
} Lexer;
|
||||
|
||||
static void readName(Lexer* lexer);
|
||||
static void readNumber(Lexer* lexer);
|
||||
static void readString(Lexer* lexer);
|
||||
static void readEmbedded(Lexer* lexer);
|
||||
static void readWhitespace(Lexer* lexer);
|
||||
static int isKeyword(Lexer* lexer, const char* keyword);
|
||||
static int isName(char c);
|
||||
static int isDigit(char c);
|
||||
static char advance(Lexer* lexer);
|
||||
static char peek(Lexer* lexer);
|
||||
static void emitToken(Lexer* lexer, TokenType type);
|
||||
|
||||
Token* tokenize(Buffer* source)
|
||||
{
|
||||
Lexer lexer;
|
||||
lexer.source = source;
|
||||
lexer.start = 0;
|
||||
lexer.pos = 0;
|
||||
lexer.head = NULL;
|
||||
lexer.tail = NULL;
|
||||
|
||||
while (peek(&lexer) != '\0')
|
||||
{
|
||||
lexer.start = lexer.pos;
|
||||
|
||||
char c = advance(&lexer);
|
||||
switch (c)
|
||||
{
|
||||
case '(': emitToken(&lexer, TOKEN_LEFT_PAREN); break;
|
||||
case ')': emitToken(&lexer, TOKEN_RIGHT_PAREN); break;
|
||||
case '[': emitToken(&lexer, TOKEN_LEFT_BRACKET); break;
|
||||
case ']': emitToken(&lexer, TOKEN_RIGHT_BRACKET); break;
|
||||
case '{': emitToken(&lexer, TOKEN_LEFT_BRACE); break;
|
||||
case '}': emitToken(&lexer, TOKEN_RIGHT_BRACE); break;
|
||||
case ':': emitToken(&lexer, TOKEN_COLON); break;
|
||||
case '.': emitToken(&lexer, TOKEN_DOT); break;
|
||||
case ',': emitToken(&lexer, TOKEN_COMMA); break;
|
||||
case '*': emitToken(&lexer, TOKEN_STAR); break;
|
||||
case '/': emitToken(&lexer, TOKEN_SLASH); break;
|
||||
case '%': emitToken(&lexer, TOKEN_PERCENT); break;
|
||||
case '+': emitToken(&lexer, TOKEN_PLUS); break;
|
||||
case '-': emitToken(&lexer, TOKEN_MINUS); break;
|
||||
case '|': emitToken(&lexer, TOKEN_PIPE); break;
|
||||
case '&': emitToken(&lexer, TOKEN_AMP); break;
|
||||
case '=':
|
||||
if (peek(&lexer) == '=')
|
||||
{
|
||||
advance(&lexer);
|
||||
emitToken(&lexer, TOKEN_EQEQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitToken(&lexer, TOKEN_EQ);
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
if (peek(&lexer) == '=')
|
||||
{
|
||||
advance(&lexer);
|
||||
emitToken(&lexer, TOKEN_LTEQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitToken(&lexer, TOKEN_LT);
|
||||
}
|
||||
break;
|
||||
|
||||
case '>':
|
||||
if (peek(&lexer) == '=')
|
||||
{
|
||||
advance(&lexer);
|
||||
emitToken(&lexer, TOKEN_GTEQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitToken(&lexer, TOKEN_GT);
|
||||
}
|
||||
break;
|
||||
|
||||
case '!':
|
||||
if (peek(&lexer) == '=')
|
||||
{
|
||||
advance(&lexer);
|
||||
emitToken(&lexer, TOKEN_BANGEQ);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitToken(&lexer, TOKEN_BANG);
|
||||
}
|
||||
break;
|
||||
|
||||
case '\n': emitToken(&lexer, TOKEN_LINE); break;
|
||||
|
||||
case ' ': readWhitespace(&lexer); break;
|
||||
case '"': readString(&lexer); break;
|
||||
case '`': readEmbedded(&lexer); break;
|
||||
|
||||
default:
|
||||
if (isName(c))
|
||||
{
|
||||
readName(&lexer);
|
||||
}
|
||||
else if (isDigit(c))
|
||||
{
|
||||
readNumber(&lexer);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitToken(&lexer, TOKEN_ERROR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lexer.start = lexer.pos;
|
||||
emitToken(&lexer, TOKEN_EOF);
|
||||
|
||||
return lexer.head;
|
||||
}
|
||||
|
||||
static void readName(Lexer* lexer)
|
||||
{
|
||||
// TODO(bob): Handle digits and EOF.
|
||||
while (isName(peek(lexer)) || isDigit(peek(lexer))) advance(lexer);
|
||||
|
||||
TokenType type = TOKEN_NAME;
|
||||
|
||||
if (isKeyword(lexer, "else")) type = TOKEN_ELSE;
|
||||
else if (isKeyword(lexer, "if")) type = TOKEN_IF;
|
||||
else if (isKeyword(lexer, "var")) type = TOKEN_VAR;
|
||||
|
||||
emitToken(lexer, type);
|
||||
}
|
||||
|
||||
static int isKeyword(Lexer* lexer, const char* keyword)
|
||||
{
|
||||
size_t length = lexer->pos - lexer->start;
|
||||
size_t keywordLength = strlen(keyword);
|
||||
return length == keywordLength &&
|
||||
strncmp(lexer->source->bytes + lexer->start, keyword, length) == 0;
|
||||
}
|
||||
|
||||
static void readNumber(Lexer* lexer)
|
||||
{
|
||||
// TODO(bob): Floating point, hex, scientific, etc.
|
||||
while (isDigit(peek(lexer))) advance(lexer);
|
||||
|
||||
emitToken(lexer, TOKEN_NUMBER);
|
||||
}
|
||||
|
||||
static void readString(Lexer* lexer)
|
||||
{
|
||||
// TODO(bob): Escape sequences, EOL, EOF, etc.
|
||||
while (advance(lexer) != '"');
|
||||
|
||||
emitToken(lexer, TOKEN_STRING);
|
||||
}
|
||||
|
||||
static void readEmbedded(Lexer* lexer)
|
||||
{
|
||||
// TODO(bob): EOF.
|
||||
while (advance(lexer) != '`');
|
||||
|
||||
emitToken(lexer, TOKEN_EMBEDDED);
|
||||
}
|
||||
|
||||
static void readWhitespace(Lexer* lexer)
|
||||
{
|
||||
while (peek(lexer) == ' ') advance(lexer);
|
||||
|
||||
emitToken(lexer, TOKEN_WHITESPACE);
|
||||
}
|
||||
|
||||
static int isName(char c)
|
||||
{
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
|
||||
}
|
||||
|
||||
static int isDigit(char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
static char advance(Lexer* lexer)
|
||||
{
|
||||
char c = peek(lexer);
|
||||
lexer->pos++;
|
||||
return c;
|
||||
}
|
||||
|
||||
static char peek(Lexer* lexer)
|
||||
{
|
||||
return lexer->source->bytes[lexer->pos];
|
||||
}
|
||||
|
||||
static void emitToken(Lexer* lexer, TokenType type)
|
||||
{
|
||||
Token* token = newToken(type, lexer->start, lexer->pos);
|
||||
|
||||
token->prev = lexer->tail;
|
||||
token->next = NULL;
|
||||
|
||||
if (lexer->tail == NULL)
|
||||
{
|
||||
// First token.
|
||||
lexer->head = token;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not the first token, so add it to the end.
|
||||
lexer->tail->next = token;
|
||||
}
|
||||
|
||||
lexer->tail = token;
|
||||
}
|
||||
8
src/lexer.h
Normal file
8
src/lexer.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef wren_lexer_h
|
||||
#define wren_lexer_h
|
||||
|
||||
#include "token.h"
|
||||
|
||||
Token* tokenize(Buffer* source);
|
||||
|
||||
#endif
|
||||
71
src/main.c
Normal file
71
src/main.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lexer.h"
|
||||
#include "parser.h"
|
||||
|
||||
#define MAX_FILE_SIZE 256 * 256
|
||||
|
||||
static void dumpTokens(Buffer* buffer, Token* token);
|
||||
|
||||
Buffer* readFile(const char* path)
|
||||
{
|
||||
FILE* file = fopen(path, "r");
|
||||
// TODO(bob): Handle error.
|
||||
|
||||
Buffer* buffer = newBuffer(MAX_FILE_SIZE);
|
||||
// TODO(bob): Hacky way to read a file!
|
||||
size_t read = fread(buffer->bytes, sizeof(char), MAX_FILE_SIZE, file);
|
||||
buffer->bytes[read] = '\0';
|
||||
|
||||
fclose(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
// TODO(bob): Validate command line arguments.
|
||||
Buffer* buffer = readFile(argv[1]);
|
||||
Token* tokens = tokenize(buffer);
|
||||
//printf("Raw tokens:\n");
|
||||
//dumpTokens(buffer, tokens);
|
||||
//printf("Cleaned tokens:\n");
|
||||
dumpTokens(buffer, tokens);
|
||||
|
||||
/*Node* node =*/ parse(buffer, tokens);
|
||||
|
||||
/*
|
||||
if (defns) generate(buffer, defns);
|
||||
|
||||
// TODO(bob): Free tokens.
|
||||
// TODO(bob): Free ast.
|
||||
*/
|
||||
|
||||
freeBuffer(buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dumpTokens(Buffer* buffer, Token* token)
|
||||
{
|
||||
while (token)
|
||||
{
|
||||
switch (token->type)
|
||||
{
|
||||
case TOKEN_INDENT: printf("(in)"); break;
|
||||
case TOKEN_OUTDENT: printf("(out)"); break;
|
||||
case TOKEN_LINE: printf("(line)"); break;
|
||||
case TOKEN_ERROR: printf("(error)"); break;
|
||||
case TOKEN_EOF: printf("(eof)"); break;
|
||||
default:
|
||||
printf("⊏");
|
||||
for (int i = token->start; i < token->end; i++)
|
||||
{
|
||||
putchar(buffer->bytes[i]);
|
||||
}
|
||||
printf("⊐");
|
||||
}
|
||||
token = token->next;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
349
src/parser.c
Normal file
349
src/parser.c
Normal file
@ -0,0 +1,349 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "parser.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Buffer* source;
|
||||
Token* current;
|
||||
|
||||
// Non-zero if a parse error has occurred.
|
||||
int hasError;
|
||||
} Parser;
|
||||
|
||||
typedef Node* (*PrefixParserFn)(Parser*, Token*);
|
||||
typedef Node* (*InfixParserFn)(Parser*, Node*, Token*);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
InfixParserFn fn;
|
||||
int precedence;
|
||||
} InfixParser;
|
||||
|
||||
static Node* block(Parser* parser);
|
||||
static Node* statementLike(Parser* parser);
|
||||
static Node* expression(Parser* parser);
|
||||
static Node* parsePrecedence(Parser* parser, int precedence);
|
||||
static Node* prefixLiteral(Parser* parser, Token* token);
|
||||
static Node* infixCall(Parser* parser, Node* left, Token* token);
|
||||
static Node* infixBinaryOp(Parser* parser, Node* left, Token* token);
|
||||
static TokenType peek(Parser* parser);
|
||||
static Token* match(Parser* parser, TokenType expected);
|
||||
static Token* consume(Parser* parser, TokenType expected);
|
||||
static Token* advance(Parser* parser);
|
||||
static void error(Parser* parser, const char* format, ...);
|
||||
|
||||
enum
|
||||
{
|
||||
PREC_NONE,
|
||||
PREC_LOWEST,
|
||||
|
||||
PREC_EQUALITY, // == !=
|
||||
PREC_COMPARISON, // < > <= >=
|
||||
PREC_BITWISE, // | &
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / %
|
||||
PREC_CALL // ()
|
||||
};
|
||||
|
||||
PrefixParserFn prefixParsers[] = {
|
||||
NULL, // TOKEN_LEFT_PAREN
|
||||
NULL, // TOKEN_RIGHT_PAREN
|
||||
NULL, // TOKEN_LEFT_BRACKET
|
||||
NULL, // TOKEN_RIGHT_BRACKET
|
||||
NULL, // TOKEN_LEFT_BRACE
|
||||
NULL, // TOKEN_RIGHT_BRACE
|
||||
NULL, // TOKEN_COLON
|
||||
NULL, // TOKEN_DOT
|
||||
NULL, // TOKEN_COMMA
|
||||
NULL, // TOKEN_STAR
|
||||
NULL, // TOKEN_SLASH
|
||||
NULL, // TOKEN_PERCENT
|
||||
NULL, // TOKEN_PLUS
|
||||
NULL, // TOKEN_MINUS
|
||||
NULL, // TOKEN_PIPE
|
||||
NULL, // TOKEN_AMP
|
||||
NULL, // TOKEN_BANG
|
||||
NULL, // TOKEN_EQ
|
||||
NULL, // TOKEN_LT
|
||||
NULL, // TOKEN_GT
|
||||
NULL, // TOKEN_LTEQ
|
||||
NULL, // TOKEN_GTEQ
|
||||
NULL, // TOKEN_EQEQ
|
||||
NULL, // TOKEN_BANGEQ
|
||||
NULL, // TOKEN_ELSE
|
||||
NULL, // TOKEN_IF
|
||||
NULL, // TOKEN_VAR
|
||||
NULL, // TOKEN_EMBEDDED
|
||||
prefixLiteral, // TOKEN_NAME
|
||||
prefixLiteral, // TOKEN_NUMBER
|
||||
prefixLiteral, // TOKEN_STRING
|
||||
NULL, // TOKEN_LINE
|
||||
NULL, // TOKEN_WHITESPACE
|
||||
NULL, // TOKEN_INDENT
|
||||
NULL, // TOKEN_OUTDENT
|
||||
NULL, // TOKEN_ERROR
|
||||
NULL // TOKEN_EOF
|
||||
};
|
||||
|
||||
// The indices in this array correspond to TOKEN enum values.
|
||||
InfixParser infixParsers[] = {
|
||||
{ infixCall, PREC_CALL }, // TOKEN_LEFT_PAREN
|
||||
{ NULL, PREC_NONE }, // TOKEN_RIGHT_PAREN
|
||||
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACKET
|
||||
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACKET
|
||||
{ NULL, PREC_NONE }, // TOKEN_LEFT_BRACE
|
||||
{ NULL, PREC_NONE }, // TOKEN_RIGHT_BRACE
|
||||
{ NULL, PREC_NONE }, // TOKEN_COLON
|
||||
{ NULL, PREC_NONE }, // TOKEN_DOT
|
||||
{ NULL, PREC_NONE }, // TOKEN_COMMA
|
||||
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_STAR
|
||||
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_SLASH
|
||||
{ infixBinaryOp, PREC_FACTOR }, // TOKEN_PERCENT
|
||||
{ infixBinaryOp, PREC_TERM }, // TOKEN_PLUS
|
||||
{ infixBinaryOp, PREC_TERM }, // TOKEN_MINUS
|
||||
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_PIPE
|
||||
{ infixBinaryOp, PREC_BITWISE }, // TOKEN_AMP
|
||||
{ NULL, PREC_NONE }, // TOKEN_BANG
|
||||
{ NULL, PREC_NONE }, // TOKEN_EQ
|
||||
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LT
|
||||
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GT
|
||||
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_LTEQ
|
||||
{ infixBinaryOp, PREC_COMPARISON }, // TOKEN_GTEQ
|
||||
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_EQEQ
|
||||
{ infixBinaryOp, PREC_EQUALITY }, // TOKEN_BANGEQ
|
||||
{ NULL, PREC_NONE }, // TOKEN_ELSE
|
||||
{ NULL, PREC_NONE }, // TOKEN_IF
|
||||
{ NULL, PREC_NONE }, // TOKEN_VAR
|
||||
{ NULL, PREC_NONE }, // TOKEN_EMBEDDED
|
||||
{ NULL, PREC_NONE }, // TOKEN_NAME
|
||||
{ NULL, PREC_NONE }, // TOKEN_NUMBER
|
||||
{ NULL, PREC_NONE }, // TOKEN_STRING
|
||||
{ NULL, PREC_NONE }, // TOKEN_LINE
|
||||
{ NULL, PREC_NONE }, // TOKEN_WHITESPACE
|
||||
{ NULL, PREC_NONE }, // TOKEN_INDENT
|
||||
{ NULL, PREC_NONE }, // TOKEN_OUTDENT
|
||||
{ NULL, PREC_NONE }, // TOKEN_ERROR
|
||||
{ NULL, PREC_NONE } // TOKEN_EOF
|
||||
};
|
||||
|
||||
Node* parse(Buffer* source, Token* tokens)
|
||||
{
|
||||
Parser parser;
|
||||
parser.source = source;
|
||||
parser.current = tokens;
|
||||
parser.hasError = 0;
|
||||
|
||||
NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence));
|
||||
sequence->node.type = NODE_SEQUENCE;
|
||||
sequence->nodes = NULL;
|
||||
|
||||
// TODO(bob): Copied from block(). Unify.
|
||||
NodeList** nodes = &sequence->nodes;
|
||||
do
|
||||
{
|
||||
Node* node = statementLike(&parser);
|
||||
*nodes = (NodeList*)malloc(sizeof(NodeList));
|
||||
(*nodes)->node = node;
|
||||
(*nodes)->next = NULL;
|
||||
nodes = &(*nodes)->next;
|
||||
|
||||
} while (!match(&parser, TOKEN_EOF));
|
||||
|
||||
return parser.hasError ? NULL : (Node*)sequence;
|
||||
}
|
||||
|
||||
static Node* block(Parser* parser)
|
||||
{
|
||||
consume(parser, TOKEN_INDENT);
|
||||
|
||||
NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence));
|
||||
sequence->node.type = NODE_SEQUENCE;
|
||||
sequence->nodes = NULL;
|
||||
|
||||
NodeList** nodes = &sequence->nodes;
|
||||
do
|
||||
{
|
||||
Node* node = statementLike(parser);
|
||||
*nodes = (NodeList*)malloc(sizeof(NodeList));
|
||||
(*nodes)->node = node;
|
||||
(*nodes)->next = NULL;
|
||||
nodes = &(*nodes)->next;
|
||||
|
||||
} while (!match(parser, TOKEN_OUTDENT));
|
||||
|
||||
return (Node*)sequence;
|
||||
}
|
||||
|
||||
static Node* statementLike(Parser* parser)
|
||||
{
|
||||
if (match(parser, TOKEN_IF))
|
||||
{
|
||||
Node* condition = expression(parser);
|
||||
consume(parser, TOKEN_COLON);
|
||||
Node* thenArm = block(parser);
|
||||
Node* elseArm = NULL;
|
||||
if (match(parser, TOKEN_ELSE))
|
||||
{
|
||||
consume(parser, TOKEN_COLON);
|
||||
elseArm = block(parser);
|
||||
}
|
||||
|
||||
NodeIf* expr = (NodeIf*)malloc(sizeof(NodeIf));
|
||||
expr->node.type = NODE_IF;
|
||||
expr->condition = condition;
|
||||
expr->thenArm = thenArm;
|
||||
expr->elseArm = elseArm;
|
||||
return (Node*)expr;
|
||||
}
|
||||
|
||||
if (match(parser, TOKEN_VAR))
|
||||
{
|
||||
Token* name = consume(parser, TOKEN_NAME);
|
||||
Node* initializer = NULL;
|
||||
if (match(parser, TOKEN_EQ))
|
||||
{
|
||||
initializer = expression(parser);
|
||||
}
|
||||
if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE);
|
||||
|
||||
NodeVar* node = (NodeVar*)malloc(sizeof(NodeVar));
|
||||
node->node.type = NODE_VAR;
|
||||
node->name = name;
|
||||
node->initializer = initializer;
|
||||
return (Node*)node;
|
||||
}
|
||||
|
||||
// Statement expression.
|
||||
Node* node = expression(parser);
|
||||
if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static Node* expression(Parser* parser)
|
||||
{
|
||||
return parsePrecedence(parser, PREC_LOWEST);
|
||||
}
|
||||
|
||||
Node* parsePrecedence(Parser* parser, int precedence)
|
||||
{
|
||||
Token* token = advance(parser);
|
||||
PrefixParserFn prefix = prefixParsers[token->type];
|
||||
|
||||
if (prefix == NULL)
|
||||
{
|
||||
// TODO(bob): Handle error better.
|
||||
error(parser, "No prefix parser.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Node* left = prefix(parser, token);
|
||||
|
||||
while (precedence <= infixParsers[parser->current->type].precedence)
|
||||
{
|
||||
token = advance(parser);
|
||||
InfixParserFn infix = infixParsers[token->type].fn;
|
||||
left = infix(parser, left, token);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
static Node* prefixLiteral(Parser* parser, Token* token)
|
||||
{
|
||||
NodeLiteral* node = (NodeLiteral*)malloc(sizeof(NodeLiteral));
|
||||
node->node.type = NODE_LITERAL;
|
||||
node->token = token;
|
||||
return (Node*)node;
|
||||
}
|
||||
|
||||
static Node* infixCall(Parser* parser, Node* left, Token* token)
|
||||
{
|
||||
NodeList* args = NULL;
|
||||
if (match(parser, TOKEN_RIGHT_PAREN) == NULL)
|
||||
{
|
||||
NodeList** arg = &args;
|
||||
do
|
||||
{
|
||||
*arg = (NodeList*)malloc(sizeof(NodeList));
|
||||
(*arg)->node = expression(parser);
|
||||
(*arg)->next = NULL;
|
||||
arg = &(*arg)->next;
|
||||
}
|
||||
while (match(parser, TOKEN_COMMA) != NULL);
|
||||
|
||||
consume(parser, TOKEN_RIGHT_PAREN);
|
||||
}
|
||||
|
||||
NodeCall* node = (NodeCall*)malloc(sizeof(NodeCall));
|
||||
node->node.type = NODE_CALL;
|
||||
node->fn = left;
|
||||
node->args = args;
|
||||
|
||||
return (Node*)node;
|
||||
}
|
||||
|
||||
static Node* infixBinaryOp(Parser* parser, Node* left, Token* token)
|
||||
{
|
||||
// TODO(bob): Support right-associative infix. Needs to do precedence
|
||||
// - 1 here to be right-assoc.
|
||||
Node* right = parsePrecedence(parser,
|
||||
infixParsers[token->type].precedence);
|
||||
|
||||
NodeBinaryOp* node = (NodeBinaryOp*)malloc(sizeof(NodeBinaryOp));
|
||||
node->node.type = NODE_BINARY_OP;
|
||||
node->left = left;
|
||||
node->op = token;
|
||||
node->right = right;
|
||||
|
||||
return (Node*)node;
|
||||
}
|
||||
|
||||
static TokenType peek(Parser* parser)
|
||||
{
|
||||
return parser->current->type;
|
||||
}
|
||||
|
||||
static Token* match(Parser* parser, TokenType expected)
|
||||
{
|
||||
if (peek(parser) != expected) return NULL;
|
||||
|
||||
return advance(parser);
|
||||
}
|
||||
|
||||
static Token* consume(Parser* parser, TokenType expected)
|
||||
{
|
||||
Token* token = advance(parser);
|
||||
if (token->type != expected)
|
||||
{
|
||||
// TODO(bob): Better error.
|
||||
error(parser, "Expected %d, got %d.\n", expected, token->type);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
static Token* advance(Parser* parser)
|
||||
{
|
||||
// TODO(bob): Check for EOF.
|
||||
Token* token = parser->current;
|
||||
parser->current = parser->current->next;
|
||||
return unlinkToken(token);
|
||||
}
|
||||
|
||||
static void error(Parser* parser, const char* format, ...)
|
||||
{
|
||||
parser->hasError = 1;
|
||||
printf("Parse error on '");
|
||||
printToken(parser->source, parser->current);
|
||||
|
||||
printf("': ");
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
90
src/parser.h
Normal file
90
src/parser.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef wren_parser_h
|
||||
#define wren_parser_h
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
// AST nodes.
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NODE_LITERAL,
|
||||
NODE_SEQUENCE,
|
||||
NODE_CALL,
|
||||
NODE_BINARY_OP,
|
||||
NODE_IF,
|
||||
NODE_VAR,
|
||||
|
||||
NODE_MAX
|
||||
} NodeType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NodeType type;
|
||||
} Node;
|
||||
|
||||
typedef struct NodeList_s
|
||||
{
|
||||
Node* node;
|
||||
struct NodeList_s* next;
|
||||
} NodeList;
|
||||
|
||||
// Numbers, strings, variable names.
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
Token* token;
|
||||
} NodeLiteral;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
NodeList* nodes;
|
||||
} NodeSequence;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
Node* fn;
|
||||
NodeList* args;
|
||||
} NodeCall;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
Token* op;
|
||||
Node* left;
|
||||
Node* right;
|
||||
} NodeBinaryOp;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
Node* condition;
|
||||
Node* thenArm;
|
||||
Node* elseArm;
|
||||
} NodeIf;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Node node;
|
||||
Token* name;
|
||||
Node* initializer;
|
||||
} NodeVar;
|
||||
|
||||
// Parameters.
|
||||
|
||||
// TODO(bob): Is this needed?
|
||||
typedef struct
|
||||
{
|
||||
Token* name;
|
||||
} Param;
|
||||
|
||||
typedef struct ParamList_s
|
||||
{
|
||||
Param* param;
|
||||
struct ParamList_s* next;
|
||||
} ParamList;
|
||||
|
||||
Node* parse(Buffer* source, Token* tokens);
|
||||
|
||||
#endif
|
||||
49
src/token.c
Normal file
49
src/token.c
Normal file
@ -0,0 +1,49 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "token.h"
|
||||
|
||||
Buffer* newBuffer(size_t size)
|
||||
{
|
||||
Buffer* buffer = (Buffer*)malloc(sizeof(Buffer));
|
||||
buffer->bytes = (char*)malloc(size);
|
||||
buffer->size = size;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void freeBuffer(Buffer* buffer)
|
||||
{
|
||||
free(buffer->bytes);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
Token* newToken(TokenType type, int start, int end)
|
||||
{
|
||||
Token* token = (Token*)malloc(sizeof(Token));
|
||||
token->type = type;
|
||||
token->start = start;
|
||||
token->end = end;
|
||||
token->prev = NULL;
|
||||
token->next = NULL;
|
||||
return token;
|
||||
}
|
||||
|
||||
void printToken(Buffer* buffer, Token* token)
|
||||
{
|
||||
for (int i = token->start; i < token->end; i++)
|
||||
{
|
||||
putchar(buffer->bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Token* unlinkToken(Token* token)
|
||||
{
|
||||
if (token->next) token->next->prev = token->prev;
|
||||
if (token->prev) token->prev->next = token->next;
|
||||
|
||||
token->next = NULL;
|
||||
token->prev = NULL;
|
||||
|
||||
return token;
|
||||
}
|
||||
84
src/token.h
Normal file
84
src/token.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef wren_token_h
|
||||
#define wren_token_h
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// TODO(bob): Move somewhere else?
|
||||
typedef struct Buffer_s
|
||||
{
|
||||
char* bytes;
|
||||
size_t size;
|
||||
} Buffer;
|
||||
|
||||
// Note: if you add new token types, make sure to update the parser arrays in
|
||||
// parser.c.
|
||||
typedef enum
|
||||
{
|
||||
TOKEN_LEFT_PAREN,
|
||||
TOKEN_RIGHT_PAREN,
|
||||
TOKEN_LEFT_BRACKET,
|
||||
TOKEN_RIGHT_BRACKET,
|
||||
TOKEN_LEFT_BRACE,
|
||||
TOKEN_RIGHT_BRACE,
|
||||
TOKEN_COLON,
|
||||
TOKEN_DOT,
|
||||
TOKEN_COMMA,
|
||||
TOKEN_STAR,
|
||||
TOKEN_SLASH,
|
||||
TOKEN_PERCENT,
|
||||
TOKEN_PLUS,
|
||||
TOKEN_MINUS,
|
||||
TOKEN_PIPE,
|
||||
TOKEN_AMP,
|
||||
TOKEN_BANG,
|
||||
TOKEN_EQ,
|
||||
TOKEN_LT,
|
||||
TOKEN_GT,
|
||||
TOKEN_LTEQ,
|
||||
TOKEN_GTEQ,
|
||||
TOKEN_EQEQ,
|
||||
TOKEN_BANGEQ,
|
||||
|
||||
TOKEN_ELSE,
|
||||
TOKEN_IF,
|
||||
TOKEN_VAR,
|
||||
|
||||
TOKEN_EMBEDDED,
|
||||
TOKEN_NAME,
|
||||
TOKEN_NUMBER,
|
||||
TOKEN_STRING,
|
||||
|
||||
TOKEN_LINE,
|
||||
TOKEN_WHITESPACE,
|
||||
TOKEN_INDENT,
|
||||
TOKEN_OUTDENT,
|
||||
|
||||
TOKEN_ERROR,
|
||||
TOKEN_EOF,
|
||||
|
||||
MAX_TOKEN
|
||||
} TokenType;
|
||||
|
||||
typedef struct Token_s
|
||||
{
|
||||
TokenType type;
|
||||
int start;
|
||||
int end;
|
||||
|
||||
struct Token_s* prev;
|
||||
struct Token_s* next;
|
||||
} Token;
|
||||
|
||||
Buffer* newBuffer(size_t size);
|
||||
void freeBuffer(Buffer* buffer);
|
||||
|
||||
// Creates a new unlinked token.
|
||||
Token* newToken(TokenType type, int start, int end);
|
||||
|
||||
// Prints the verbatim source text of the token.
|
||||
void printToken(Buffer* buffer, Token* token);
|
||||
|
||||
// Removes the token from the list containing it. Does not free it.
|
||||
Token* unlinkToken(Token* token);
|
||||
|
||||
#endif
|
||||
79
src/wren.1
Normal file
79
src/wren.1
Normal file
@ -0,0 +1,79 @@
|
||||
.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
|
||||
.\"See Also:
|
||||
.\"man mdoc.samples for a complete listing of options
|
||||
.\"man mdoc for the short list of editing options
|
||||
.\"/usr/share/misc/mdoc.template
|
||||
.Dd 10/22/13 \" DATE
|
||||
.Dt wren 1 \" Program name and manual section number
|
||||
.Os Darwin
|
||||
.Sh NAME \" Section Header - required - don't modify
|
||||
.Nm wren,
|
||||
.\" The following lines are read in generating the apropos(man -k) database. Use only key
|
||||
.\" words here as the database is built based on the words here and in the .ND line.
|
||||
.Nm Other_name_for_same_program(),
|
||||
.Nm Yet another name for the same program.
|
||||
.\" Use .Nm macro to designate other names for the documented program.
|
||||
.Nd This line parsed for whatis database.
|
||||
.Sh SYNOPSIS \" Section Header - required - don't modify
|
||||
.Nm
|
||||
.Op Fl abcd \" [-abcd]
|
||||
.Op Fl a Ar path \" [-a path]
|
||||
.Op Ar file \" [file]
|
||||
.Op Ar \" [file ...]
|
||||
.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
|
||||
arg2 ... \" Arguments
|
||||
.Sh DESCRIPTION \" Section Header - required - don't modify
|
||||
Use the .Nm macro to refer to your program throughout the man page like such:
|
||||
.Nm
|
||||
Underlining is accomplished with the .Ar macro like this:
|
||||
.Ar underlined text .
|
||||
.Pp \" Inserts a space
|
||||
A list of items with descriptions:
|
||||
.Bl -tag -width -indent \" Begins a tagged list
|
||||
.It item a \" Each item preceded by .It macro
|
||||
Description of item a
|
||||
.It item b
|
||||
Description of item b
|
||||
.El \" Ends the list
|
||||
.Pp
|
||||
A list of flags and their descriptions:
|
||||
.Bl -tag -width -indent \" Differs from above in tag removed
|
||||
.It Fl a \"-a flag as a list item
|
||||
Description of -a flag
|
||||
.It Fl b
|
||||
Description of -b flag
|
||||
.El \" Ends the list
|
||||
.Pp
|
||||
.\" .Sh ENVIRONMENT \" May not be needed
|
||||
.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
|
||||
.\" .It Ev ENV_VAR_1
|
||||
.\" Description of ENV_VAR_1
|
||||
.\" .It Ev ENV_VAR_2
|
||||
.\" Description of ENV_VAR_2
|
||||
.\" .El
|
||||
.Sh FILES \" File used or created by the topic of the man page
|
||||
.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
|
||||
.It Pa /usr/share/file_name
|
||||
FILE_1 description
|
||||
.It Pa /Users/joeuser/Library/really_long_file_name
|
||||
FILE_2 description
|
||||
.El \" Ends the list
|
||||
.\" .Sh DIAGNOSTICS \" May not be needed
|
||||
.\" .Bl -diag
|
||||
.\" .It Diagnostic Tag
|
||||
.\" Diagnostic informtion here.
|
||||
.\" .It Diagnostic Tag
|
||||
.\" Diagnostic informtion here.
|
||||
.\" .El
|
||||
.Sh SEE ALSO
|
||||
.\" List links in ascending order by section, alphabetically within a section.
|
||||
.\" Please do not reference files that do not exist without filing a bug report
|
||||
.Xr a 1 ,
|
||||
.Xr b 1 ,
|
||||
.Xr c 1 ,
|
||||
.Xr a 2 ,
|
||||
.Xr b 2 ,
|
||||
.Xr a 3 ,
|
||||
.Xr b 3
|
||||
.\" .Sh BUGS \" Document known, unremedied bugs
|
||||
.\" .Sh HISTORY \" Document history if command behaves in a unique manner
|
||||
249
wren.xcodeproj/project.pbxproj
Normal file
249
wren.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,249 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
29AB1F281816E49C004B501E /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F1E1816E49C004B501E /* lexer.c */; };
|
||||
29AB1F291816E49C004B501E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F201816E49C004B501E /* main.c */; };
|
||||
29AB1F2A1816E49C004B501E /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F211816E49C004B501E /* parser.c */; };
|
||||
29AB1F2C1816E49C004B501E /* token.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F251816E49C004B501E /* token.c */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
29AB1F041816E3AD004B501E /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
29AB1F1E1816E49C004B501E /* lexer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lexer.c; path = src/lexer.c; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F1F1816E49C004B501E /* lexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lexer.h; path = src/lexer.h; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F201816E49C004B501E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F211816E49C004B501E /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parser.c; path = src/parser.c; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F221816E49C004B501E /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parser.h; path = src/parser.h; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F251816E49C004B501E /* token.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = token.c; path = src/token.c; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F261816E49C004B501E /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = token.h; path = src/token.h; sourceTree = SOURCE_ROOT; };
|
||||
29AB1F271816E49C004B501E /* wren.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = wren.1; path = src/wren.1; sourceTree = SOURCE_ROOT; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
29AB1F031816E3AD004B501E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
29AB1EFD1816E3AD004B501E = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29AB1F081816E3AD004B501E /* src */,
|
||||
29AB1F071816E3AD004B501E /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29AB1F071816E3AD004B501E /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29AB1F061816E3AD004B501E /* wren */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
29AB1F081816E3AD004B501E /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29AB1F1E1816E49C004B501E /* lexer.c */,
|
||||
29AB1F1F1816E49C004B501E /* lexer.h */,
|
||||
29AB1F201816E49C004B501E /* main.c */,
|
||||
29AB1F211816E49C004B501E /* parser.c */,
|
||||
29AB1F221816E49C004B501E /* parser.h */,
|
||||
29AB1F251816E49C004B501E /* token.c */,
|
||||
29AB1F261816E49C004B501E /* token.h */,
|
||||
29AB1F271816E49C004B501E /* wren.1 */,
|
||||
);
|
||||
name = src;
|
||||
path = wren;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
29AB1F051816E3AD004B501E /* wren */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 29AB1F0F1816E3AD004B501E /* Build configuration list for PBXNativeTarget "wren" */;
|
||||
buildPhases = (
|
||||
29AB1F021816E3AD004B501E /* Sources */,
|
||||
29AB1F031816E3AD004B501E /* Frameworks */,
|
||||
29AB1F041816E3AD004B501E /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = wren;
|
||||
productName = wren;
|
||||
productReference = 29AB1F061816E3AD004B501E /* wren */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
29AB1EFE1816E3AD004B501E /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0500;
|
||||
ORGANIZATIONNAME = "Bob Nystrom";
|
||||
};
|
||||
buildConfigurationList = 29AB1F011816E3AD004B501E /* Build configuration list for PBXProject "wren" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 29AB1EFD1816E3AD004B501E;
|
||||
productRefGroup = 29AB1F071816E3AD004B501E /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
29AB1F051816E3AD004B501E /* wren */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
29AB1F021816E3AD004B501E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
29AB1F291816E49C004B501E /* main.c in Sources */,
|
||||
29AB1F2A1816E49C004B501E /* parser.c in Sources */,
|
||||
29AB1F2C1816E49C004B501E /* token.c in Sources */,
|
||||
29AB1F281816E49C004B501E /* lexer.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
29AB1F0D1816E3AD004B501E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
29AB1F0E1816E3AD004B501E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
SDKROOT = macosx;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
29AB1F101816E3AD004B501E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
29AB1F111816E3AD004B501E /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
29AB1F011816E3AD004B501E /* Build configuration list for PBXProject "wren" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
29AB1F0D1816E3AD004B501E /* Debug */,
|
||||
29AB1F0E1816E3AD004B501E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
29AB1F0F1816E3AD004B501E /* Build configuration list for PBXNativeTarget "wren" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
29AB1F101816E3AD004B501E /* Debug */,
|
||||
29AB1F111816E3AD004B501E /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 29AB1EFE1816E3AD004B501E /* Project object */;
|
||||
}
|
||||
7
wren.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
wren.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:wren.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
Reference in New Issue
Block a user