/* main program logic: spawn crud to see what happens */ int main ( int argc, char * * argv, char * * env ) { char mode; int cnt; mode = toupper( argv[ 1 ][ 0 ]); cnt = atoi( argv[ 2 ]); if ( mode == 'T') { do_threads( cnt); } // threads? else if ( mode == 'F') { do_forks( cnt); } // forks? else if ( mode == 'S') { do_sequence( cnt); } // sequential processing? else { die( "Arg 1 must be T (thread), F (fork), or S (sequential)"); } return 0; }
// Type Function // ----------------------------------------------------------------------------- // function-type-parameter = [ "identifier" ":" ] type ; // function-type = "(" ")" "->" type // | "(" function-type-parameter { "," function-type-parameter } [ "," ] ")" "->" type // ; // ----------------------------------------------------------------------------- bool Parser::parse_type_function(Ref<ast::TypeTuple> initial, bool in_params) { // Declare the tuple-type node Ref<ast::TypeFunction> node = new ast::TypeFunction(initial->span); // Consume parsed type parameters (so far) for (auto& elem : initial->elements) { node->parameters.push_back(new ast::TypeParameter( elem->span, "", elem, false )); } if (in_params) { // Iterate and parse each parameter in the sequence if (!do_sequence(Token::Type::RightParenthesis, [&, this]() { // Check for `[MUTABLE] IDENTIFIER ":"` to allow for the keyword auto begin = _t.peek(0)->span; std::string keyword = ""; bool is_mutable = false; if ((_t.peek(0)->type == Token::Type::Identifier && _t.peek(1)->type == Token::Type::Colon) || ( _t.peek(0)->type == Token::Type::Mutable && _t.peek(1)->type == Token::Type::Identifier && _t.peek(2)->type == Token::Type::Colon)) { if (_t.peek(0)->type == Token::Type::Mutable) { _t.pop(); is_mutable = true; } auto id = expect<ast::Identifier>(&Parser::parse_identifier); keyword = id->text; _t.pop(); // ":" } // Parse the element auto type = expect(&Parser::parse_type); if (!type) return false; // Push the element node->parameters.push_back(new ast::TypeParameter( begin.extend(type->span), keyword, type, is_mutable )); return true; })) return false; // Expect a `)` auto tok = expect(Token::Type::RightParenthesis); if (!tok) return false; node->span = node->span.extend(tok->span); } // Expect a `->` auto tok = expect(Token::Type::Arrow); if (!tok) return false; node->span = node->span.extend(tok->span); node->result = expect<ast::Type>(&Parser::parse_type); if (!node->result) return false; // Push the node _stack.push_front(node); return true; }
// Pattern // ----------------------------------------------------------------------------- // pattern-wildcard = "_" ; // pattern-literal = literal ; // pattern-identifier = [ "mutable" ] IDENTIFIER ; // pattern-tuple = // | "(" ")" // | "(" pattern "," ")" // | "(" pattern "," pattern "," pattern [ "," ] ")" // ; // pattern = pattern-wildcard // | pattern-literal // | pattern-identifier // | pattern-tuple ; // ----------------------------------------------------------------------------- bool Parser::parse_pattern() { auto tok = _t.peek(0); // Check for a "_" which would indicate a wildcard pattern if (tok->type == Token::Type::Underscore) { auto tok = _t.pop(); _stack.push_front(new ast::PatternWildcard(tok->span)); return true; } // Check for a `mut` which could optionally preceed an identifier pattern bool mut = false; if (tok->type == Token::Type::Mutable && _t.peek(1)->type == Token::Type::Identifier) { _t.pop(); tok = _t.peek(0); mut = true; } // Check for an IDENTIFIER which would indicate a simple identifier pattern if (tok->type == Token::Type::Identifier) { auto ident = expect<ast::Identifier>(&Parser::parse_identifier); if (!ident) return false; _stack.push_front(new ast::PatternIdentifier(tok->span, ident->text, mut)); return true; } // Check for a `(` which would be the start of a tuple pattern if (tok->type == Token::Type::LeftParenthesis) { _t.pop(); // Declare the tuple-pattern node Ref<ast::PatternTuple> node = new ast::PatternTuple(tok->span); // Check for an immediate `)` which makes this an empty tuple if (_t.peek(0)->type == Token::Type::RightParenthesis) { tok = _t.pop(); node->span = node->span.extend(tok->span); _stack.push_front(node); return true; } // Parse the first element (which is a special case for tuples) auto elem0 = expect(&Parser::parse_pattern); if (!elem0) return false; node->elements.push_back(elem0); // Expect a comma to follow the first element (to prove we're a tuple) if (!expect(Token::Type::Comma)) return false; // Iterate and parse each remaining element in the sequence if (!do_sequence(Token::Type::RightParenthesis, [&, this]() { // Parse the element auto elem = expect(&Parser::parse_pattern); if (!elem) return false; // Push the element node->elements.push_back(elem); return true; })) return false; // Expect `)` if (!(tok = expect(Token::Type::RightParenthesis))) { return false; } // Push the node node->span = node->span.extend(tok->span); _stack.push_front(node); return true; } // Check for and parse a literal for a literal pattern if (tok->type == Token::Type::Float || tok->type == Token::Type::String || tok->type == Token::Type::Integer || tok->type == Token::Type::True || tok->type == Token::Type::None || tok->type == Token::Type::False) { auto literal = expect<ast::Literal>(&Parser::parse_literal); if (!literal) return false; _stack.push_front(new ast::PatternLiteral(tok->span, literal)); return true; } // TODO: Additional patterns // Fail; could not match a pattern // TODO: Should probably have shorter error message expect({ Token::Type::Mutable, Token::Type::Identifier, Token::Type::LeftParenthesis, Token::Type::Underscore, Token::Type::Float, Token::Type::True, Token::Type::False, Token::Type::Integer, Token::Type::String, Token::Type::None }); return false; }
// Type // ----------------------------------------------------------------------------- // type = identifier // | "None" // | "*" type // | "(" ")" // | "(" type "," ")" // | "(" type "," type { "," type } [ "," ] ")" // | function-type // ; // ----------------------------------------------------------------------------- bool Parser::parse_type() { auto tok = _t.peek(0); if (!([&, this]() -> bool { // Check for `None` to indicate the unit type if (tok->type == Token::Type::None) { auto tok = _t.pop(); _stack.push_front(new ast::TypeNone(tok->span)); return true; } // Check for an identifier (for a simple type) if (tok->type == Token::Type::Identifier) { std::vector<std::string> segments; auto span = tok->span; for (unsigned i = 0; ; i++) { // Expect a `.` (unless this is the first identifier) if (i > 0 && !expect(Token::Type::Period)) return false; // Parse the identifier auto id_node = expect<ast::Identifier>(&Parser::parse_identifier); if (!id_node) return false; segments.push_back(id_node->text); // Extend the span span = span.extend(id_node->span); // Check for a `.` that could continue this into a path if (_t.peek(0)->type != Token::Type::Period) break; } _stack.push_front(new ast::TypePath( span, segments )); return true; } // Check for a `type(..)` to indicate a typeOf if (tok->type == Token::Type::TypeOf) { auto span = tok->span; _t.pop(); // Expect a `(` if (!expect(Token::Type::LeftParenthesis)) return false; // Parse an expression if (!parse_expression()) return false; auto expr = _stack.front(); _stack.pop_front(); // Expect a `)` auto last_tok = expect(Token::Type::RightParenthesis); if (!last_tok) return false; _stack.push_front(new ast::TypeOf( span.extend(last_tok->span), expr )); return true; } // Check for a `*` to indicate a pointer type if (tok->type == Token::Type::Asterisk) { _t.pop(); // Check for `mutable` to indicate a mutable pointee bool is_mutable = false; if (_t.peek(0)->type == Token::Type::Mutable) { _t.pop(); is_mutable = true; } // Parse the pointee type auto pointee = expect(&Parser::parse_type); if (!pointee) return false; _stack.push_front(new ast::TypePointer( tok->span.extend(pointee->span), pointee, is_mutable )); return true; } // Check for a `(` which would be the start of a tuple type OR a // function type if (tok->type == Token::Type::LeftParenthesis) { _t.pop(); // Declare the tuple-type node Ref<ast::TypeTuple> node = new ast::TypeTuple(tok->span); // Check for an immediate `)` which makes this an empty tuple if (_t.peek(0)->type == Token::Type::RightParenthesis) { tok = _t.pop(); node->span = node->span.extend(tok->span); // Check for a "->" (which would make this definitely be // a function type) if (_t.peek(0)->type == Token::Type::Arrow) { return parse_type_function(node, false); } _stack.push_front(node); return true; } // Check for a named parameter (which would make this definitely be // a function type) if (_t.peek(0)->type == Token::Type::Identifier && _t.peek(1)->type == Token::Type::Colon) { return parse_type_function(node); } // Parse the first element (which is a special case for tuples) auto elem0 = expect(&Parser::parse_type); if (!elem0) return false; node->elements.push_back(elem0); // Check for an arrow (which would make this definitely be // a function type) if (_t.peek(0)->type == Token::Type::RightParenthesis && _t.peek(1)->type == Token::Type::Arrow) { _t.pop(); return parse_type_function(node, false); } // Check for an immediate `)` which makes this just a grouping if (_t.peek()->type == Token::Type::RightParenthesis) { _t.pop(); _stack.push_front(elem0); return true; } // Expect a comma to follow the first element (to prove we're a tuple) if (!expect(Token::Type::Comma)) return false; // Iterate and parse each remaining element in the sequence if (!do_sequence(Token::Type::RightParenthesis, [&, this]() { // Check for a named parameter (which would make this definitely be // a function type) if (_t.peek(0)->type == Token::Type::Identifier && _t.peek(1)->type == Token::Type::Colon) { return parse_type_function(node); } // Parse the element auto elem = expect(&Parser::parse_type); if (!elem) return false; // Push the element node->elements.push_back(elem); return true; })) return false; // Expect `)` if (!(tok = expect(Token::Type::RightParenthesis))) { return false; } node->span = node->span.extend(tok->span); // Check for a "->" (which would make this definitely be // a function type) if (_t.peek(0)->type == Token::Type::Arrow) { return parse_type_function(node, false); } // Push the node _stack.push_front(node); return true; } // TODO: type(X) // Fail; could not match a pattern // TODO: Should probably have shorter error message expect({ Token::Type::Identifier, Token::Type::LeftParenthesis, Token::Type::Asterisk, Token::Type::None }); return false; })()) { return false; } // Attempt to match successive `[..]` to make this an array type while (_t.peek()->type == Token::Type::LeftBracket) { _t.pop(); // Pull the element type expression auto element = _stack.front(); _stack.pop_front(); // Check for an immediate `]` to indicate an unsized or dynamic array if (_t.peek()->type == Token::Type::RightBracket) { auto last_tok = _t.pop(); _stack.push_front(new ast::TypeArray( element->span.extend(last_tok->span), element )); } // Parse an expression for the size if (!parse_expression()) return false; auto size = _stack.front(); _stack.pop_front(); // Expect an `]` to close the array type auto last_tok = expect(Token::Type::RightBracket); _stack.push_front(new ast::TypeArray( element->span.extend(last_tok->span), element, size )); } return true; }
// Structure // ----------------------------------------------------------------------------- // struct = [ "export" ] "struct" IDENTIFIER "{" [ struct-members ] "}" ; // struct-members = struct-member { "," struct-member } [ "," ] ; // struct-member = IDENTIFIER ":" type [ "=" expression ] ; // ----------------------------------------------------------------------------- bool Parser::parse_struct() { // Check for "export" Ref<Token> initial_tok = nullptr; bool exported = false; if (_t.peek()->type == Token::Type::Export) { exported = true; initial_tok = _t.pop(); } // Expect `struct` auto tok = expect(Token::Type::Struct); if (!tok) return false; if (!initial_tok) initial_tok = tok; // Expect an identifier auto id = expect<ast::Identifier>(&Parser::parse_identifier); if (!id) return false; auto name = id->text; // Expect `{` if (!expect(Token::Type::LeftBrace)) return false; // Declare the node Ref<ast::Structure> node = new ast::Structure( initial_tok->span, exported, name); // Iterate and parse each argument in the sequence if (!do_sequence(Token::Type::RightBrace, [&, this]() { // Expect an identifier auto id = expect<ast::Identifier>(&Parser::parse_identifier); if (!id) return false; // Expect `:` if (!expect(Token::Type::Colon)) return false; // Parse type annotation auto annotation = expect<ast::Type>(&Parser::parse_type); auto last_span = annotation->span; if (!annotation) return false; // Check for an `=` which would indicate a default value Ref<ast::Node> val = nullptr; if (_t.peek()->type == Token::Type::Equals) { _t.pop(); if (!parse_expression()) return false; val = _stack.front(); last_span = val->span; _stack.pop_front(); } // Declare and push the member node->members.push_back(new ast::Member( id->span.extend(last_span), id->text, annotation, val)); return true; })) return false; // Expect `}` if (!expect(Token::Type::RightBrace)) return false; // Push the node _stack.push_front(node); return true; }