Example #1
0
static int DSCP_parse(int c, char **argv, int invert, unsigned int *flags,
                      const void *entry, struct xt_entry_target **target)
{
	struct xt_DSCP_info *dinfo
		= (struct xt_DSCP_info *)(*target)->data;

	switch (c) {
	case 'F':
		if (*flags)
			xtables_error(PARAMETER_PROBLEM,
			           "DSCP target: Only use --set-dscp ONCE!");
		parse_dscp(optarg, dinfo);
		*flags = 1;
		break;
	case 'G':
		if (*flags)
			xtables_error(PARAMETER_PROBLEM,
				   "DSCP target: Only use --set-dscp-class ONCE!");
		parse_class(optarg, dinfo);
		*flags = 1;
		break;

	default:
		return 0;
	}

	return 1;
}
Example #2
0
// using [class] id (id ...) (renaming id->id id->id) (hiding id ... id)
environment using_cmd(parser & p) {
    environment env = p.env();
    while (true) {
        name cls = parse_class(p);
        bool decls = cls.is_anonymous() || cls == g_decls || cls == g_declarations;
        auto pos   = p.pos();
        name ns    = p.check_id_next("invalid 'using' command, identifier expected");
        optional<name> real_ns = to_valid_namespace_name(env, ns);
        if (!real_ns)
            throw parser_error(sstream() << "invalid namespace name '" << ns << "'", pos);
        ns = *real_ns;
        env = using_namespace(env, p.ios(), ns, cls);
        if (decls) {
            // Remark: we currently to not allow renaming and hiding of universe levels
            buffer<name> exceptions;
            bool found_explicit = false;
            while (p.curr_is_token(g_lparen)) {
                p.next();
                if (p.curr_is_token_or_id(g_renaming)) {
                    p.next();
                    while (p.curr_is_identifier()) {
                        name from_id = p.get_name_val();
                        p.next();
                        p.check_token_next(g_arrow, "invalid 'using' command renaming, '->' expected");
                        name to_id = p.check_id_next("invalid 'using' command renaming, identifier expected");
                        check_identifier(p, env, ns, from_id);
                        exceptions.push_back(from_id);
                        env = add_expr_alias(env, to_id, ns+from_id);
                    }
                } else if (p.curr_is_token_or_id(g_hiding)) {
                    p.next();
                    while (p.curr_is_identifier()) {
                        name id = p.get_name_val();
                        p.next();
                        check_identifier(p, env, ns, id);
                        exceptions.push_back(id);
                    }
                } else if (p.curr_is_identifier()) {
                    found_explicit = true;
                    while (p.curr_is_identifier()) {
                        name id = p.get_name_val();
                        p.next();
                        check_identifier(p, env, ns, id);
                        env = add_expr_alias(env, id, ns+id);
                    }
                } else {
                    throw parser_error("invalid 'using' command option, identifier, 'hiding' or 'renaming' expected", p.pos());
                }
                if (found_explicit && !exceptions.empty())
                    throw parser_error("invalid 'using' command option, mixing explicit and implicit 'using' options", p.pos());
                p.check_token_next(g_rparen, "invalid 'using' command option, ')' expected");
            }
            if (!found_explicit)
                env = add_aliases(env, ns, name(), exceptions.size(), exceptions.data());
        }
        if (!p.curr_is_token(g_lbracket) && !p.curr_is_identifier())
            break;
    }
    return env;
}
Example #3
0
static int
dscp_parse(int c, char **argv, int invert, unsigned int *flags,
           const void *entry, struct xt_entry_match **match)
{
	struct xt_dscp_info *dinfo
		= (struct xt_dscp_info *)(*match)->data;

	switch (c) {
	case 'F':
		if (*flags)
			xtables_error(PARAMETER_PROBLEM,
			           "DSCP match: Only use --dscp ONCE!");
		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
		parse_dscp(optarg, dinfo);
		if (invert)
			dinfo->invert = 1;
		*flags = 1;
		break;

	case 'G':
		if (*flags)
			xtables_error(PARAMETER_PROBLEM,
					"DSCP match: Only use --dscp-class ONCE!");
		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
		parse_class(optarg, dinfo);
		if (invert)
			dinfo->invert = 1;
		*flags = 1;
		break;
	}

	return 1;
}
Example #4
0
/* bitvectors (i.e., powers of two) for each class, mainly for use in do_who
 * and do_users.  Add new classes at the end so that all classes use sequential
 * powers of two (1 << 0, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, etc.) up to
 * the limit of your bitvector_t, typically 0-31. */
bitvector_t find_class_bitvector(const char *arg)
{
  size_t rpos, ret = 0;

  for (rpos = 0; rpos < strlen(arg); rpos++)
    ret |= (1 << parse_class(arg[rpos]));

  return (ret);
}
Example #5
0
static Cpattern
parse_pattern(char *name, char **sp, int *lp, char e, int *err)
{
    Cpattern ret = NULL, r = NULL, n;
    char *s = *sp;
    convchar_t inchar;
    int l = 0, inlen;

    *err = 0;

    MB_METACHARINIT();
    while (*s && (e ? (*s != e) : !inblank(*s))) {
	n = (Cpattern) hcalloc(sizeof(*n));
	n->next = NULL;

	if (*s == '[' || *s == '{') {
	    s = parse_class(n, s);
	    if (!*s) {
		*err = 1;
		zwarnnam(name, "unterminated character class");
		return NULL;
	    }
	    s++;
	} else if (*s == '?') {
	    n->tp = CPAT_ANY;
	    s++;
	} else if (*s == '*' || *s == '(' || *s == ')' || *s == '=') {
	    *err = 1;
	    zwarnnam(name, "invalid pattern character `%c'", *s);
	    return NULL;
	} else {
	    if (*s == '\\' && s[1])
		s++;

	    inlen = MB_METACHARLENCONV(s, &inchar);
#ifdef MULTIBYTE_SUPPORT
	    if (inchar == WEOF)
		inchar = (convchar_t)(*s == Meta ? s[1] ^ 32 : *s);
#endif
	    s += inlen;
	    n->tp = CPAT_CHAR;
	    n->u.chr = inchar;
	}
	if (ret)
	    r->next = n;
	else
	    ret = n;

	r = n;

	l++;
    }
    *sp = (char *) s;
    *lp = l;
    return ret;
}
Example #6
0
static void
makeTags (xmlNode *node, const gchar *parent)
{
	g_assert (node != NULL);
	g_assert (node->name != NULL);

	if (strcmp ((const gchar*)node->name, "text") == 0
			|| strcmp ((const gchar*)node->name, "implements") == 0)
		return;
	if (strcmp ((const gchar*)node->name, "enumeration") == 0
			|| strcmp ((const gchar*)node->name, "union") == 0
			|| strcmp ((const gchar*)node->name, "namespace") == 0
			|| strcmp ((const gchar*)node->name, "class") == 0
			|| strcmp ((const gchar*)node->name, "record") == 0
			|| strcmp ((const gchar*)node->name, "bitfield") == 0
			|| strcmp ((const gchar*)node->name, "interface") == 0)
	{
		parse_class (node);
		return;
	}
	if (strcmp ((const gchar*)node->name, "function") == 0 || strcmp ((const gchar*)node->name, "method") == 0
			|| strcmp ((const gchar*)node->name, "callback") == 0
			|| strcmp ((const gchar*)node->name, "constructor") == 0)
	{
		parse_function (node, parent);
		return;
	}
	if (strcmp ((const gchar*)node->name, "alias") == 0 ||
			strcmp ((const gchar*)node->name, "constant") == 0 ||
			strcmp ((const gchar*)node->name, "signal") == 0 ||
			strcmp ((const gchar*)node->name, "field") == 0 ||
			strcmp ((const gchar*)node->name, "property") == 0 ||
			strcmp ((const gchar*)node->name, "member") == 0)
	{
		gchar *name = (gchar*)xmlGetProp (node, (const xmlChar*)"name");
		if (!name)
			return;
		tagEntryInfo *tag = (tagEntryInfo*)malloc (sizeof (tagEntryInfo));
		initTagEntry (tag, name);
		tag->isFileScope	= 1;
		tag->kindName = "variable";
		tag->kind = 'v';
		get_file_pos (node->line, &tag->filePosition, File.fp);
		tag->lineNumber = node->line;
		if (parent) {
			tag->kindName = "member";
			tag->kind = 'm';
			tag->extensionFields.scope[0] = "class";
			tag->extensionFields.scope[1] = parent;
		}
		makeTagEntry (tag);
		return;
	}
}
Example #7
0
void ProguardMap::parse_line(const std::string& line) {
  if (parse_class(line)) {
    return;
  }
  if (parse_field(line)) {
    return;
  }
  if (parse_method(line)) {
    return;
  }
  always_assert_log(false,
                    "Bogus line encountered in proguard map: %s\n",
                    line.c_str());
}
Example #8
0
void convert_file(const char *filename, const char *input, FILE *h, FILE *cpp)
{
	int		t;
	const char	*s, *e;
	Lex		lex(filename, input);

	for(;;) {
		t = lex.GetToken();
		if(t == '\0') {
			break;
		}
		lex.Write(h);
		if(t == Lex::IDENTIFIER) {
			s = lex.GetStart();
			e = lex.GetEnd();
			if(e - s == 5 && memcmp(s, "class", 5) == 0) {
				parse_class(lex, h, cpp);
			}
		}
	}
}
static int
parse(int c, char **argv, int invert, unsigned int *flags,
      const struct ipt_entry *entry,
      unsigned int *nfcache,
      struct ipt_entry_match **match)
{
	struct ipt_dscp_info *dinfo
		= (struct ipt_dscp_info *)(*match)->data;

	switch (c) {
	case 'F':
		if (*flags)
			exit_error(PARAMETER_PROBLEM,
			           "DSCP match: Only use --dscp ONCE!");
		check_inverse(optarg, &invert, &optind, 0);
		parse_dscp(argv[optind-1], dinfo);
		if (invert)
			dinfo->invert = 1;
		*flags = 1;
		break;

	case 'G':
		if (*flags)
			exit_error(PARAMETER_PROBLEM,
					"DSCP match: Only use --dscp-class ONCE!");
		check_inverse(optarg, &invert, &optind, 0);
		parse_class(argv[optind - 1], dinfo);
		if (invert)
			dinfo->invert = 1;
		*flags = 1;
		break;

	default:
		return 0;
	}

	return 1;
}
Example #10
0
string
r_language_rep::get_color (tree t, int start, int end) {
  static bool setup_done= false;
  if (!setup_done) {
    r_color_setup_constants (colored);
    r_color_setup_keywords (colored);
    r_color_setup_otherlexeme (colored);
    setup_done= true;
  }

  static string none= "";
  if (start >= end) return none;
  string s= t->label;
  string r1=s(0,start) ;

  int pos=0;int opos;
  bool backquote= false;
  bool after_backquote;
  bool postfix= false;
  bool possible_function= true;
  bool possible_type= false;
  bool possible_class= false;
  bool possible_future_type= false;
  bool possible_future_function= true;
  bool possible_future_class= false;
  string type;
  bool is_markup;

#if 0
  // There isn't much point to the following, because its only effet is pos and type, and both are reset below.
  do {
    do {
      opos=pos;

      parse_string (s, pos);
      if (opos<pos) break;

      parse_comment_single_line (s, pos);
      if (opos < pos) {
	type= "comment";
	break;
      }

      pos++;
    } while(false);
  } while( pos<N(s) );
#endif 

  pos=0;
  do {
    type= none;
    do {
      after_backquote= backquote;
      possible_function= possible_future_function;
      possible_type= possible_future_type;
      possible_class= possible_future_class;
      opos= pos;

      parse_blanks (s, pos);
      if (opos<pos) break;

      parse_string (s, pos);
      if (opos<pos) {
	type= "string";
	backquote= false;
	postfix= false;
	possible_future_function= false;
	possible_future_type= false;
	possible_future_class= false;
	possible_type= false;
	break;
      }

      parse_number (s, pos);
      if (opos<pos) {
	type= "number";
	backquote= false;
	postfix= false;
	possible_future_function= false;
	possible_future_class= false;
	break;
      }

      parse_comment_single_line (s, pos);
      if (opos<pos) {
	type= "comment";
	backquote= false;
	postfix= false;
	possible_future_type= false;
	possible_type= false;
	break;
      }

      parse_modifier (colored, s, pos);
      if (opos<pos) {
	type="keyword";
	backquote= false;
	postfix= false;
	possible_future_type= false;
	possible_type= false;
	possible_function= false;
	break;
      }

      parse_postfix (colored, s, pos);
      if (opos<pos) {
	type="keyword";
	backquote= false;
	postfix= true;
	possible_future_type= false;
	possible_future_class= false;
	possible_type= false;
	possible_function= false;
	possible_future_class= false;
	break;
      }

      parse_class (colored, s, pos);
      if (opos<pos) {
	type= "keyword";
	backquote=false;
	postfix=false;
	possible_future_type= false;
	possible_type= false;
	possible_future_class=true;
	possible_future_function= false;
	break;
      }

      parse_keyword (colored, s, pos);
      if (opos<pos) {
	type= "keyword";
	backquote= false;
	postfix= false;
	possible_future_type= false;
	possible_type= false;
	possible_function= false;
	possible_future_function= false;
	possible_future_class= false;
	break;
      }

      parse_other_op_assign (colored, s, pos);  //not left parenthesis
      if (opos<pos) {
	type= "other_lexeme";// was
	type = "op assign" ;
	backquote= false;
	postfix= false;
	possible_function= false;
	possible_future_function= true;
	possible_future_type= false;
	possible_future_class= false;
	possible_type= false;
	break;
      }

      parse_other_op_index (colored, s, pos);  //not left parenthesis
      if (opos<pos) {
	type= "other_lexeme";// was
	type = "op index" ;
	backquote= false;
	postfix= false;
	possible_function= false;
	possible_future_function= true;
	possible_future_type= false;
	possible_future_class= false;
	possible_type= false;
	break;
      }

      parse_other_lexeme (colored, s, pos);  //not left parenthesis
      if (opos<pos) {
	type= "other_lexeme";// was
	type = "operator" ;
	backquote= false;
	postfix= false;
	possible_function= false;
	possible_future_function= true;
	possible_future_type= false;
	possible_future_class= false;
	possible_type= false;
	break;
      }

      parse_constant (colored, s, pos);
      if (opos<pos) {
	type= "constant";
	backquote= false;
	postfix= false;
	possible_future_function= false;
	possible_future_class= false;
	break;
      }


      parse_backquote (s, pos);
      if (opos<pos) {
	backquote= true;
	postfix= false;
	possible_future_function= false;
	possible_future_class= false;
	break;
      }

      parse_identifier_or_markup (colored, s, pos, postfix, is_markup);
      if (opos<pos) {
	if (is_markup) {type= "identifier_markup";} else type= "identifier";
	backquote= false;
	postfix= false;
	possible_future_function=false;
	possible_future_class= false;
	break;
      }

      parse_parenthesized (s, pos);
      // stops after well parenthesized ) or before  // or /{ or " or /"
      if (opos<pos && pos<=start) {
	type="left_parenthesis";
	backquote= false;
	postfix= false;
	possible_function= false;
	possible_future_function= true;
	possible_future_class= false;
	break;
      }
      if (opos<pos && possible_type==true)
	return "dark green";
      if (opos<pos && after_backquote)  
	return none;

      backquote= false;
      postfix= false;
      pos= opos;
      pos++;
    } while (false); // This while() is so that we can easily escape with break.
  } while (pos<=start);

  if (possible_type) return "dark green";
  if (type=="string") return "#a06040";
  if (type=="operator") return "red";
  if (type=="op assign") return "dark green";
  if (type=="op index") return "dark blue";
  if (type=="comment") return "brown";
  if (type=="keyword" && !after_backquote) return "#8020c0";
  if (type=="other_lexeme") return none;
  if (type=="constant") return "#2060c0";
  if (type=="number") return "#2060c0";
  if (type=="left_parenthesis") return none;
  if (type=="identifier" && !possible_function && !possible_class )  return none;
  if (type=="identifier_markup" && !possible_function && !possible_class ) return COLOR_MARKUP;

  if ( (type=="identifier" || type=="identifier_markup") && possible_function) {
    possible_function= false;
    do {
      do {
	opos=pos;
	parse_blanks (s, pos);
	if (opos<pos) break;

	parse_identifier (colored, s, pos,false);
	if (opos<pos) { possible_function= true; break; }

	parse_number (s, pos);
	if (opos<pos) { possible_function= true; break; }

	parse_constant (colored, s, pos);
	if (opos<pos) { possible_function= true; break; }

	parse_comment_single_line (s, pos);
	if (opos<pos) break;

	parse_parenthesized (s, pos);
	if (opos<pos) { possible_function= true; break; }

      } while (false);
    } while (opos != pos);

    if (!possible_function) {
      if (type=="identifier") {return none;} 
      else return COLOR_MARKUP; // type=="identifier_markup"
    } else do {
	do {
	  opos=pos;
	  parse_blanks (s, pos);
	  if (opos<pos) break;
	  parse_identifier (colored, s, pos,false);
	  if (opos<pos) break;
	  parse_number(s,pos);
	  if (opos<pos) break;
	  parse_constant (colored, s, pos);
	  if (opos<pos) break;
	  parse_comment_single_line(s,pos);
	  if (opos<pos) break;
	  parse_parenthesized (s, pos);
	  if (opos<pos) break;

	  if (type=="identifier") {return none;} 
	  else return COLOR_MARKUP;

	} while (false);
      }
      while (pos<N(s));
  } // type==identifier || type==identifier_markup && possible function

  if ( (type=="identifier" || type=="identifier_markup") && possible_class) {
    do {
      do {
	opos=pos;
	parse_blanks (s, pos);
	if (opos<pos) break;

	parse_identifier (colored, s, pos,false);
	if (opos<pos) break;

	parse_number(s,pos);
	if (opos<pos) break;

	parse_constant (colored, s, pos);
	if (opos<pos) break;

	parse_comment_single_line(s,pos);
	if (opos<pos) break;

	parse_parenthesized (s, pos);
	if (opos<pos) break;

	if (type=="identifier") {return none;} 
	else return COLOR_MARKUP;
      } while (false);
    }
    while (pos<N(s));
  }
  if (type=="identifier_markup") {return COLOR_MARKUP;}
  else return none;
}
Example #11
0
File: peg.c Project: ctelfer/catlib
static int parse_primary(struct peg_grammar_parser *pgp, struct peg_cursor *pc,
			 int *prip)
{
	struct peg_grammar *peg = pgp->peg;
	int pri;
	int rv;
	int match = -1;
	struct peg_cursor npc = *pc;
	int prefix = PEG_ATTR_NONE;
	int suffix = PEG_ATTR_NONE;
	int action = PEG_ACT_NONE;
	struct raw r = { 0, NULL };
	struct peg_node *pn;

	if ( string_match(pgp, "&", &npc) )
		prefix = PEG_ATTR_AND;
	else if ( string_match(pgp, "!", &npc) )
		prefix = PEG_ATTR_NOT;

	if ( (rv = parse_id_and_not_arrow(pgp, &npc, &match)) != 0 ) {
		if ( rv < 0 )
			goto err;
	} else if ( (rv = parse_paren_expr(pgp, &npc, &match)) != 0 ) {
		if ( rv < 0 )
			goto err;
	} else if ( (rv = parse_literal(pgp, &npc, &match)) != 0 ) {
		if ( rv < 0 )
			goto err;
	} else if ( (rv = parse_class(pgp, &npc, &match)) != 0 ) {
		if ( rv < 0 )
			goto err;
	} else {
		if ( prefix == PEG_ATTR_NONE )
			return 0;
		pgp->err = PEG_ERR_BAD_PRIMARY;
		pgp->eloc = *pc;
		return -1;
	}

	pri = peg_node_new(peg, PEG_PRIMARY, pc->line);
	if ( pri < 0 ) {
		pgp->err = PEG_ERR_NOMEM;
		goto err;
	}

	if ( string_match(pgp, "?", &npc) )
		suffix = PEG_ATTR_QUESTION;
	else if ( string_match(pgp, "*", &npc) )
		suffix = PEG_ATTR_STAR;
	else if ( string_match(pgp, "+", &npc) )
		suffix = PEG_ATTR_PLUS;
	else
		suffix = PEG_ATTR_NONE;

	rv = parse_code(pgp, &npc, &r);
	if ( rv < 0 )
		goto err;
	if ( rv > 0 ) {
		action = PEG_ACT_CODE;
	} else {
		rv = parse_action_label(pgp, &npc, &r);
		if ( rv < 0 )
			goto err;
		if ( rv > 0 )
			action = PEG_ACT_LABEL;
	}

	pn = NODE(peg, pri);
	pn->pn_next = -1;
	pn->pp_match = match;
	pn->pp_prefix = prefix;
	pn->pp_suffix = suffix;
	pn->pp_action = action;
	pn->pn_action_cb = NULL;
	pn->pp_code = r;

	*pc = npc;
	*prip = pri;
	return 1;

err:
	peg_node_free(peg, match);
	return -1;
}
Example #12
0
void parse_class(Lex& lex, FILE *h, FILE *cpp)
{
	int		t, l, brackets;
	const char	*s, *e;

	do {
		t = lex.GetToken();
		lex.Write(h);
	} while(isspace(t) || t == '\n');
	if(t != Lex::IDENTIFIER) {
		// is it possible that we don't have an identifier after the keyword class?!
		fprintf(stderr, "%s:%ld: error: expected an identifier after the 'class' keyword\n", lex.Filename(), lex.Line());
		g_errcnt++;
		return;
	}
	// we got the class name!
	s = lex.GetStart();
	e = lex.GetEnd();
	l = static_cast<int>(e - s);
	char* class_name = new char[l + 1];
	str_keeper sk(class_name);
	memcpy(class_name, s, l);
	class_name[l] = '\0';

	brackets = 0;
	for(;;) {
		t = lex.GetToken();
		if(t == '\0') {
			// that's a big problem in the source file!
			return;
		}
		if(t == ';') {
			if(brackets == 0) {
				// in this special case, we don't have a full declaration
				// i.e.:   class Stuff;
				lex.Write(h);
				return;
			}
		}
		else if(t == '{') {
			brackets++;
		}
		else if(t == '}') {
			if(brackets == 0) {
				fprintf(stderr, "%s:%ld: error: could not find { in a class definition\n", lex.Filename(), lex.Line());
				g_errcnt++;
			}
			else {
				brackets--;
			}
			if(brackets == 0) {
				break;
			}
		}
		else if(t == Lex::IDENTIFIER) {
			s = lex.GetStart();
			e = lex.GetEnd();
			if(e - s == 5 && memcmp(s, "class", 5) == 0) {
				// warning: this is a recursive call...
				lex.Write(h);
				parse_class(lex, h, cpp);
			}
			else if(e - s == 5 && memcmp(s, "async", 5) == 0) {
				// we found an asynchroneous function
				convert_async(lex, class_name, h, cpp);
				continue;
			}
		}
		lex.Write(h);
	}
	// once a class is being closed, we need to put the dynamic
	// functions if any were defined
	Dynamic *d = lex.GetDynamic();
	if(d != 0) {
		fprintf(h, "public:\n");
		while(d != 0) {
			d->Output(lex, h, cpp, class_name);
			d = d->Next();
		}
	}
	lex.ClearDynamic();
	// we don't expect the lexical input to be messed up by
	// the Dynamic::Output() calls...
	lex.Write(h);
}
Example #13
0
void start_regex_engine() {
   assert(!ptable);
   ptable = obhash_new( (void (*)(void*)) &free_pattern);
   word_characters = parse_class("[\\w]");
}
Example #14
0
struct node *parse_factor(struct compiler *compiler)
{
    switch (lexer_current(compiler))
    {
    case T_BEGIN:
        return parse_begin(compiler);

    case T_IF:
        return parse_if(compiler);

    case T_UNLESS:
        return parse_unless(compiler);

    case T_CASE:
        return parse_case(compiler);

    case T_CLASS:
        return parse_class(compiler);

    case T_MODULE:
        return parse_module(compiler);

    case T_DEF:
        return parse_method(compiler);

    case T_YIELD:
        return parse_yield(compiler);

    case T_RETURN:
        return parse_return(compiler);

    case T_BREAK:
        return parse_break(compiler);

    case T_NEXT:
        return parse_next(compiler);

    case T_REDO:
        return parse_redo(compiler);

    case T_SQUARE_OPEN:
    {
        struct node *result = alloc_node(compiler, N_ARRAY);

        lexer_next(compiler);

        if(lexer_current(compiler) == T_SQUARE_CLOSE)
            result->left  = 0;
        else
            result->left = parse_array_element(compiler);

        lexer_match(compiler, T_SQUARE_CLOSE);

        return result;
    }

    case T_STRING:
    {
        struct node *result = alloc_node(compiler, N_STRING);

        result->left = (void *)lexer_token(compiler)->start;

        lexer_next(compiler);

        return result;
    }

    case T_STRING_START:
    {
        struct node *result = alloc_node(compiler, N_STRING_CONTINUE);

        result->left = 0;
        result->middle = (void *)lexer_token(compiler)->start;

        lexer_next(compiler);

        result->right = parse_statements(compiler);

        while(lexer_current(compiler) == T_STRING_CONTINUE)
        {
            struct node *node = alloc_node(compiler, N_STRING_CONTINUE);

            node->left = result;
            node->middle = (void *)lexer_token(compiler)->start;

            lexer_next(compiler);

            node->right = parse_statements(compiler);

            result = node;
        }

        if(lexer_require(compiler, T_STRING_END))
        {
            struct node *node = alloc_node(compiler, N_STRING_START);

            node->left = result;
            node->right = (void *)lexer_token(compiler)->start;

            lexer_next(compiler);

            return node;
        }

        return result;
    }

    case T_SELF:
    {
        lexer_next(compiler);

        return &self_node;
    }

    case T_TRUE:
    {
        lexer_next(compiler);

        return alloc_node(compiler, N_TRUE);
    }

    case T_FALSE:
    {
        lexer_next(compiler);

        return alloc_node(compiler, N_FALSE);
    }

    case T_NIL:
    {
        lexer_next(compiler);

        return &nil_node;
    }

    case T_NUMBER:
    {
        struct node *result = alloc_node(compiler, N_NUMBER);

        char *text = get_token_str(lexer_token(compiler));

        result->left = (void* )atoi(text);

        lexer_next(compiler);

        return result;
    }

    case T_IVAR:
    {
        rt_value symbol = rt_symbol_from_lexer(compiler);

        lexer_next(compiler);

        switch (lexer_current(compiler))
        {
        case T_ASSIGN_ADD:
        case T_ASSIGN_SUB:
        case T_ASSIGN_MUL:
        case T_ASSIGN_DIV:
        {
            struct node *result;

            enum token_type op_type = lexer_current(compiler) - OP_TO_ASSIGN;

            lexer_next(compiler);

            result = alloc_node(compiler, N_IVAR_ASSIGN);

            result->right = alloc_node(compiler, N_BINARY_OP);
            result->right->op = op_type;
            result->right->left = alloc_node(compiler, N_IVAR);
            result->right->left->left = (void *)symbol;
            result->right->right = parse_expression(compiler);

            result->left = (void *)symbol;

            return result;
        }

        case T_ASSIGN:
        {
            struct node *result;

            lexer_next(compiler);

            result = alloc_node(compiler, N_IVAR_ASSIGN);
            result->left = (void *)symbol;
            result->right = parse_expression(compiler);

            return result;
        }

        default:
        {
            struct node *result = alloc_node(compiler, N_IVAR);

            result->left = (void *)symbol;

            return result;
        }
        }
    }

    case T_IDENT:
        return parse_identifier(compiler);

    case T_EXT_IDENT:
        return parse_call(compiler, 0, &self_node, false);

    case T_PARAM_OPEN:
    {
        lexer_next(compiler);

        struct node *result = parse_statements(compiler);

        lexer_match(compiler, T_PARAM_CLOSE);

        return result;
    }

    default:
    {
        COMPILER_ERROR(compiler, "Expected expression but found %s", token_type_names[lexer_current(compiler)]);

        lexer_next(compiler);

        return 0;
    }
    }
}