lean2/src/frontends/lean/parser_level.cpp
Leonardo de Moura 5540fc861a refactor(frontends/lean/parser): break parser in smaller chunks
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2014-01-02 06:48:40 -08:00

118 lines
3.4 KiB
C++

/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "frontends/lean/parser_imp.h"
namespace lean {
// ==========================================
// Support for parsing levels
static name g_max_name("max");
static name g_cup_name("\u2294");
static name g_plus_name("+");
static unsigned g_level_plus_prec = 10;
static unsigned g_level_cup_prec = 5;
// ==========================================
/*
Parse Universe levels
*/
level parser_imp::parse_level_max() {
auto p = pos();
next();
buffer<level> lvls;
while (curr_is_identifier() || curr_is_nat()) {
lvls.push_back(parse_level());
}
if (lvls.size() < 2)
throw parser_error("invalid level expression, max must have at least two arguments", p);
level r = lvls[0];
for (unsigned i = 1; i < lvls.size(); i++)
r = max(r, lvls[i]);
return r;
}
level parser_imp::parse_level_nud_id() {
name id = curr_name();
if (id == g_max_name) {
return parse_level_max();
} else {
next();
return m_env->get_uvar(id);
}
}
level parser_imp::parse_level_nud_int() {
auto p = pos();
mpz val = curr_num().get_numerator();
next();
if (val < 0)
throw parser_error("invalid level expression, value is negative", p);
if (!val.is_unsigned_int())
throw parser_error("invalid level expression, value does not fit in a machine integer", p);
return level() + val.get_unsigned_int();
}
level parser_imp::parse_level_lparen() {
next();
level r = parse_level();
check_rparen_next("invalid level expression, ')' expected");
return r;
}
level parser_imp::parse_level_nud() {
switch (curr()) {
case scanner::token::Id: return parse_level_nud_id();
case scanner::token::IntVal: return parse_level_nud_int();
case scanner::token::LeftParen: return parse_level_lparen();
default:
throw parser_error("invalid level expression", pos());
}
}
level parser_imp::parse_level_led_plus(level const & left) {
auto p = pos();
next();
level right = parse_level(g_level_plus_prec);
if (!is_lift(right) || !lift_of(right).is_bottom())
throw parser_error("invalid level expression, right hand side of '+' (aka universe lift operator) must be a numeral", p);
return left + lift_offset(right);
}
level parser_imp::parse_level_led_cup(level const & left) {
next();
level right = parse_level(g_level_cup_prec);
return max(left, right);
}
level parser_imp::parse_level_led(level const & left) {
switch (curr()) {
case scanner::token::Id:
if (curr_name() == g_plus_name) return parse_level_led_plus(left);
else if (curr_name() == g_cup_name) return parse_level_led_cup(left);
default:
throw parser_error("invalid level expression", pos());
}
}
unsigned parser_imp::curr_level_lbp() {
switch (curr()) {
case scanner::token::Id: {
name const & id = curr_name();
if (id == g_plus_name) return g_level_plus_prec;
else if (id == g_cup_name) return g_level_cup_prec;
else return 0;
}
default: return 0;
}
}
level parser_imp::parse_level(unsigned rbp) {
level left = parse_level_nud();
while (rbp < curr_level_lbp()) {
left = parse_level_led(left);
}
return left;
}
}