DEADSOFTWARE

Добавлен автокаст типов-записей
[dsw-obn.git] / src / oberon.c
index 382f4f182b2e98ca1032a7f720cc575e58ae9fc5..cefd46928194b60c17099c25211692000f067ff4 100644 (file)
@@ -64,7 +64,7 @@ enum {
 //   UTILS
 // ======================================================================= 
 
-void
+static void
 oberon_error(oberon_context_t * ctx, const char * fmt, ...)
 {
        va_list ptr;
@@ -98,11 +98,10 @@ oberon_new_type_integer(int size)
 }
 
 static oberon_type_t *
-oberon_new_type_boolean(int size)
+oberon_new_type_boolean()
 {
        oberon_type_t * x;
        x = oberon_new_type_ptr(OBERON_TYPE_BOOLEAN);
-       x -> size = size;
        return x;
 }
 
@@ -131,8 +130,9 @@ oberon_open_scope(oberon_context_t * ctx)
 
        if(scope -> up)
        {
-               scope -> parent = scope -> up -> parent;
                scope -> local = scope -> up -> local;
+               scope -> parent = scope -> up -> parent;
+               scope -> parent_type = scope -> up -> parent_type;
        }
 
        ctx -> decl = scope;
@@ -146,35 +146,6 @@ oberon_close_scope(oberon_scope_t * scope)
        ctx -> decl = scope -> up;
 }
 
-static oberon_object_t *
-oberon_define_object(oberon_scope_t * scope, char * name, int class, int export, int read_only)
-{
-       oberon_object_t * x = scope -> list;
-       while(x -> next && strcmp(x -> next -> name, name) != 0)
-       {
-               x = x -> next;
-       }
-
-       if(x -> next)
-       {
-               oberon_error(scope -> ctx, "already defined");
-       }
-
-       oberon_object_t * newvar = malloc(sizeof *newvar);
-       memset(newvar, 0, sizeof *newvar);
-       newvar -> name = name;
-       newvar -> class = class;
-       newvar -> export = export;
-       newvar -> read_only = read_only;
-       newvar -> local = scope -> local;
-       newvar -> parent = scope -> parent;
-       newvar -> module = scope -> ctx -> mod;
-
-       x -> next = newvar;
-
-       return newvar;
-}
-
 static oberon_object_t *
 oberon_find_object_in_list(oberon_object_t * list, char * name)
 {
@@ -187,7 +158,7 @@ oberon_find_object_in_list(oberon_object_t * list, char * name)
 }
 
 static oberon_object_t *
-oberon_find_object(oberon_scope_t * scope, char * name, int check_it)
+oberon_find_object(oberon_scope_t * scope, char * name, bool check_it)
 {
        oberon_object_t * result = NULL;
 
@@ -207,28 +178,48 @@ oberon_find_object(oberon_scope_t * scope, char * name, int check_it)
 }
 
 static oberon_object_t *
-oberon_find_field(oberon_context_t * ctx, oberon_type_t * rec, char * name)
+oberon_define_object(oberon_scope_t * scope, char * name, int class, bool export, bool read_only, bool check_upscope)
 {
-       oberon_object_t * x = rec -> decl;
-       for(int i = 0; i < rec -> num_decl; i++)
+       if(check_upscope)
        {
-               if(strcmp(x -> name, name) == 0)
+               if(oberon_find_object(scope -> up, name, false))
                {
-                       return x;
+                       oberon_error(scope -> ctx, "already defined");
                }
+       }
+
+       oberon_object_t * x = scope -> list;
+       while(x -> next && strcmp(x -> next -> name, name) != 0)
+       {
                x = x -> next;
        }
 
-       oberon_error(ctx, "field not defined");
+       if(x -> next)
+       {
+               oberon_error(scope -> ctx, "already defined");
+       }
+
+       oberon_object_t * newvar = malloc(sizeof *newvar);
+       memset(newvar, 0, sizeof *newvar);
+       newvar -> name = name;
+       newvar -> class = class;
+       newvar -> export = export;
+       newvar -> read_only = read_only;
+       newvar -> local = scope -> local;
+       newvar -> parent = scope -> parent;
+       newvar -> parent_type = scope -> parent_type;
+       newvar -> module = scope -> ctx -> mod;
+
+       x -> next = newvar;
 
-       return NULL;
+       return newvar;
 }
 
 static oberon_object_t *
 oberon_define_type(oberon_scope_t * scope, char * name, oberon_type_t * type, int export)
 {
        oberon_object_t * id;
-       id = oberon_define_object(scope, name, OBERON_CLASS_TYPE, export, 0);
+       id = oberon_define_object(scope, name, OBERON_CLASS_TYPE, export, false, false);
        id -> type = type;
        oberon_generator_init_type(scope -> ctx, type);
        return id;
@@ -444,10 +435,12 @@ oberon_read_number(oberon_context_t * ctx)
        memcpy(ident, &ctx -> code[start_i], len);
        ident[len] = 0;
 
+       ctx -> longmode = false;
        if(mode == 3)
        {
                int i = exp_i - start_i;
                ident[i] = 'E';
+               ctx -> longmode = true;
        }
 
        switch(mode)
@@ -764,34 +757,116 @@ oberon_expr_list(oberon_context_t * ctx, int * num_expr, oberon_expr_t ** first,
        }
 }
 
+static oberon_expr_t *
+oberon_cast_expr(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
+{
+       oberon_expr_t * cast;
+       cast = oberon_new_item(MODE_CAST, pref, expr -> read_only);
+       cast -> item.parent = expr;
+       cast -> next = expr -> next;
+       return cast;
+}
+
+static oberon_expr_t *
+oberno_make_record_cast(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * rec)
+{
+       if(expr -> result -> class != OBERON_TYPE_RECORD
+               || rec -> class != OBERON_TYPE_RECORD)
+       {
+               oberon_error(ctx, "must be record type");
+       }
+
+       return oberon_cast_expr(ctx, expr, rec);
+}
+
+static oberon_type_t *
+oberon_get_equal_expr_type(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b)
+{
+       oberon_type_t * result;
+       if(a -> class == OBERON_TYPE_REAL && b -> class == OBERON_TYPE_INTEGER)
+       {
+               result = a;
+       }
+       else if(b -> class == OBERON_TYPE_REAL && a -> class == OBERON_TYPE_INTEGER)
+       {
+               result = b;
+       }
+       else if(a -> class != b -> class)
+       {
+               oberon_error(ctx, "oberon_get_equal_expr_type: incompatible types");
+       }
+       else if(a -> size > b -> size)
+       {
+               result = a;
+       }
+       else
+       {
+               result = b;
+       }
+
+       return result;
+}
+
 static oberon_expr_t *
 oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t * pref)
 {
        if(pref -> class != expr -> result -> class)
        {
-               if(pref -> class != OBERON_TYPE_PROCEDURE)
+               if(pref -> class == OBERON_TYPE_POINTER)
+               {
+                       if(expr -> result -> class == OBERON_TYPE_POINTER)
+                       {
+                               // accept
+                       }
+                       else
+                       {
+                               oberon_error(ctx, "incompatible types");
+                       }
+               }
+               else if(pref -> class == OBERON_TYPE_REAL)
                {
-                       if(expr -> result -> class != OBERON_TYPE_POINTER)
+                       if(expr -> result -> class == OBERON_TYPE_INTEGER)
+                       {
+                               // accept
+                       }
+                       else
                        {
                                oberon_error(ctx, "incompatible types");
                        }
                }
+               else
+               {
+                       oberon_error(ctx, "incompatible types");
+               }
        }
 
-       if(pref -> class == OBERON_TYPE_INTEGER)
+       if(pref -> class == OBERON_TYPE_INTEGER || pref -> class == OBERON_TYPE_REAL)
        {
-               if(expr -> result -> class > pref -> class)
+               if(expr -> result -> size > pref -> size)
                {
                        oberon_error(ctx, "incompatible size");
                }
+               else
+               {
+                       expr = oberon_cast_expr(ctx, expr, pref);
+               }
        }
        else if(pref -> class == OBERON_TYPE_RECORD)
        {
-               if(expr -> result != pref)
+               oberon_type_t * t = expr -> result;
+               while(t != NULL && t != pref)
+               {
+                       t = t -> base;
+               }
+               if(t == NULL)
                {
                        printf("oberon_autocast_to: rec %p != %p\n", expr -> result, pref);
                        oberon_error(ctx, "incompatible record types");
                }
+               if(expr -> result != pref)
+               {
+                       expr = oberno_make_record_cast(ctx, expr, pref);
+               }
        }
        else if(pref -> class == OBERON_TYPE_POINTER)
        {
@@ -804,11 +879,19 @@ oberon_autocast_to(oberon_context_t * ctx, oberon_expr_t * expr, oberon_type_t *
                }
        }
 
-       // TODO cast
-
        return expr;
 }
 
+static void
+oberon_autocast_binary_op(oberon_context_t * ctx, oberon_expr_t ** ea, oberon_expr_t ** eb)
+{
+       oberon_type_t * a = (*ea) -> result;
+       oberon_type_t * b = (*eb) -> result;
+       oberon_type_t * preq = oberon_get_equal_expr_type(ctx, a, b);
+       *ea = oberon_autocast_to(ctx, *ea, preq);
+       *eb = oberon_autocast_to(ctx, *eb, preq);
+}
+
 static void
 oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
 {
@@ -840,6 +923,8 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
                oberon_error(ctx, "too many arguments");
        }
 
+       /* Делаем проверку на запись и делаем автокаст */
+       oberon_expr_t * casted[num_args];
        oberon_expr_t * arg = desig -> item.args;
        oberon_object_t * param = fn -> decl;
        for(int i = 0; i < num_args; i++)
@@ -850,27 +935,23 @@ oberon_autocast_call(oberon_context_t * ctx, oberon_expr_t * desig)
                        {
                                oberon_error(ctx, "assign to read-only var");
                        }
+               }
 
-                       //if(arg -> is_item)
-                       //{
-                       //      switch(arg -> item.mode)
-                       //      {
-                       //              case MODE_VAR:
-                       //              case MODE_INDEX:
-                       //              case MODE_FIELD:
-                       //              // Допустимо разыменование?
-                       //              //case MODE_DEREF:
-                       //                      break;
-                       //              default:
-                       //                      oberon_error(ctx, "var-parameter accept only variables");
-                       //                      break;
-                       //      }
-                       //}
-               }
-               oberon_autocast_to(ctx, arg, param -> type);
+               casted[i] = oberon_autocast_to(ctx, arg, param -> type);
                arg = arg -> next;
                param = param -> next;
        }
+
+       /* Создаём новый список выражений */
+       if(num_args > 0)
+       {
+               arg = casted[0];
+               for(int i = 0; i < num_args - 1; i++)
+               {
+                       casted[i] -> next = casted[i + 1];
+               }
+               desig -> item.args = arg;
+       }
 }
 
 static oberon_expr_t *
@@ -997,7 +1078,7 @@ oberno_make_dereferencing(oberon_context_t * ctx, oberon_expr_t * expr)
 
        oberon_expr_t * selector;
        selector = oberon_new_item(MODE_DEREF, expr -> result -> base, expr -> read_only);
-       selector -> item.parent = (oberon_item_t *) expr;
+       selector -> item.parent = expr;
 
        return selector;
 }
@@ -1044,7 +1125,7 @@ oberon_make_array_selector(oberon_context_t * ctx, oberon_expr_t * desig, oberon
 
        oberon_expr_t * selector;
        selector = oberon_new_item(MODE_INDEX, base, desig -> read_only);
-       selector -> item.parent = (oberon_item_t *) desig;
+       selector -> item.parent = desig;
        selector -> item.num_args = 1;
        selector -> item.args = index;
 
@@ -1069,7 +1150,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
        oberon_type_t * rec = expr -> result;
 
        oberon_object_t * field;
-       field = oberon_find_field(ctx, rec, name);
+       field = oberon_find_object(rec -> scope, name, true);
 
        if(field -> export == 0)
        {
@@ -1091,7 +1172,7 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
        oberon_expr_t * selector;
        selector = oberon_new_item(MODE_FIELD, field -> type, read_only);
        selector -> item.var = field;
-       selector -> item.parent = (oberon_item_t *) expr;
+       selector -> item.parent = expr;
 
        return selector;
 }
@@ -1099,7 +1180,8 @@ oberon_make_record_selector(oberon_context_t * ctx, oberon_expr_t * expr, char *
 #define ISSELECTOR(x) \
        (((x) == LBRACE) \
        || ((x) == DOT) \
-       || ((x) == UPARROW))
+       || ((x) == UPARROW) \
+       || ((x) == LPAREN))
 
 static oberon_object_t *
 oberon_qualident(oberon_context_t * ctx, char ** xname, int check)
@@ -1198,6 +1280,16 @@ oberon_designator(oberon_context_t * ctx)
                                oberon_assert_token(ctx, UPARROW);
                                expr = oberno_make_dereferencing(ctx, expr);
                                break;
+                       case LPAREN:
+                               oberon_assert_token(ctx, LPAREN);
+                               oberon_object_t * objtype = oberon_qualident(ctx, NULL, 1);
+                               if(objtype -> class != OBERON_CLASS_TYPE)
+                               {
+                                       oberon_error(ctx, "must be type");
+                               }
+                               oberon_assert_token(ctx, RPAREN);
+                               expr = oberno_make_record_cast(ctx, expr, objtype -> type);
+                               break;
                        default:
                                oberon_error(ctx, "oberon_designator: wat");
                                break;
@@ -1256,10 +1348,32 @@ oberon_opt_proc_parens(oberon_context_t * ctx, oberon_expr_t * expr)
        oberon_make_call_proc(ctx, expr -> item.var, num_args, arguments);
 }
 
+static oberon_type_t *
+oberon_get_type_of_int_value(oberon_context_t * ctx, int64_t i)
+{
+       if(i >= -128 && i <= 127)
+       {
+               return ctx -> byte_type;
+       }
+       else if(i >= -32768 && i <= 32767)
+       {
+               return ctx -> shortint_type;
+       }
+       else if(i >= -2147483648 && i <= 2147483647)
+       {
+                return ctx -> int_type;
+       }
+       else
+       {
+               return ctx -> longint_type;
+       }
+}
+
 static oberon_expr_t *
 oberon_factor(oberon_context_t * ctx)
 {
        oberon_expr_t * expr;
+       oberon_type_t * result;
 
        switch(ctx -> token)
        {
@@ -1268,23 +1382,25 @@ oberon_factor(oberon_context_t * ctx)
                        expr = oberon_opt_func_parens(ctx, expr);
                        break;
                case INTEGER:
-                       expr = oberon_new_item(MODE_INTEGER, ctx -> int_type, 1);
+                       result = oberon_get_type_of_int_value(ctx, ctx -> integer);
+                       expr = oberon_new_item(MODE_INTEGER, result, 1);
                        expr -> item.integer = ctx -> integer;
                        oberon_assert_token(ctx, INTEGER);
                        break;
                case REAL:
-                       expr = oberon_new_item(MODE_REAL, ctx -> real_type, 1);
+                       result = (ctx -> longmode) ? (ctx -> longreal_type) : (ctx -> real_type);
+                       expr = oberon_new_item(MODE_REAL, result, 1);
                        expr -> item.real = ctx -> real;
                        oberon_assert_token(ctx, REAL);
                        break;
                case TRUE:
                        expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
-                       expr -> item.boolean = 1;
+                       expr -> item.boolean = true;
                        oberon_assert_token(ctx, TRUE);
                        break;
                case FALSE:
                        expr = oberon_new_item(MODE_BOOLEAN, ctx -> bool_type, 1);
-                       expr -> item.boolean = 0;
+                       expr -> item.boolean = false;
                        oberon_assert_token(ctx, FALSE);
                        break;
                case LPAREN:
@@ -1308,41 +1424,6 @@ oberon_factor(oberon_context_t * ctx)
        return expr;
 }
 
-/*
- * oberon_autocast_binary_op автоматически переобразовывеат тип по след. правилам:
- *   1. Классы обоих типов должны быть одинаковы
- *   2. В качестве результата должен быть выбран больший тип.
- *   3. Если размер результат не должен быть меньше чем базовый int
- */
-
-static void
-oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type_t * b, oberon_type_t ** result)
-{
-       if((a -> class) != (b -> class))
-       {
-               oberon_error(ctx, "incompatible types");
-       }
-
-       if((a -> size) > (b -> size))
-       {
-               *result = a;
-       }
-       else
-       {
-               *result = b;
-       }
-
-       if(((*result) -> class) == OBERON_TYPE_INTEGER)
-       {
-               if(((*result) -> size) < (ctx -> int_type -> size))
-               {
-                       *result = ctx -> int_type;
-               }
-       }
-
-       /* TODO: cast types */
-}
-
 #define ITMAKESBOOLEAN(x) \
        (((x) >= EQUAL && (x) <= GEQ) || ((x) == OR) || ((x) == AND))
 
@@ -1352,6 +1433,27 @@ oberon_autocast_binary_op(oberon_context_t * ctx, oberon_type_t * a, oberon_type
 #define ITUSEONLYBOOLEAN(x) \
        (((x) == OR) || ((x) == AND))
 
+static void
+oberon_autocast_to_real(oberon_context_t * ctx, oberon_expr_t ** e)
+{
+       oberon_expr_t * expr = *e;
+       if(expr -> result -> class == OBERON_TYPE_INTEGER)
+       {
+               if(expr -> result -> size <= ctx -> real_type -> size)
+               {
+                       *e = oberon_cast_expr(ctx, expr, ctx -> real_type);
+               }
+               else
+               {
+                       *e = oberon_cast_expr(ctx, expr, ctx -> longreal_type);
+               }
+       }
+       else if(expr -> result -> class != OBERON_TYPE_REAL)
+       {
+               oberon_error(ctx, "required numeric type");
+       }
+}
+
 static oberon_expr_t *
 oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_expr_t * b)
 {
@@ -1362,10 +1464,12 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
        {
                if(ITUSEONLYINTEGER(token))
                {
-                       if(a -> result -> class != OBERON_TYPE_INTEGER
-                               || b -> result -> class != OBERON_TYPE_INTEGER)
+                       if(a -> result -> class == OBERON_TYPE_INTEGER
+                               || b -> result -> class == OBERON_TYPE_INTEGER
+                               || a -> result -> class == OBERON_TYPE_REAL
+                               || b -> result -> class == OBERON_TYPE_REAL)
                        {
-                               oberon_error(ctx, "used only with integer types");
+                               oberon_error(ctx, "used only with numeric types");
                        }
                }
                else if(ITUSEONLYBOOLEAN(token))
@@ -1377,6 +1481,7 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                        }
                }
 
+               oberon_autocast_binary_op(ctx, &a, &b);
                result = ctx -> bool_type;
 
                if(token == EQUAL)
@@ -1418,32 +1523,10 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
        }
        else if(token == SLASH)
        {
-               if(a -> result -> class != OBERON_TYPE_REAL)
-               {
-                       if(a -> result -> class == OBERON_TYPE_INTEGER)
-                       {
-                               oberon_error(ctx, "TODO cast int -> real");
-                       }
-                       else
-                       {
-                               oberon_error(ctx, "operator / requires numeric type");
-                       }
-               }
-
-               if(b -> result -> class != OBERON_TYPE_REAL)
-               {
-                       if(b -> result -> class == OBERON_TYPE_INTEGER)
-                       {
-                               oberon_error(ctx, "TODO cast int -> real");
-                       }
-                       else
-                       {
-                               oberon_error(ctx, "operator / requires numeric type");
-                       }
-               }
-
-               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
-               expr = oberon_new_operator(OP_DIV, result, a, b);
+               oberon_autocast_to_real(ctx, &a);
+               oberon_autocast_to_real(ctx, &b);
+               oberon_autocast_binary_op(ctx, &a, &b);
+               expr = oberon_new_operator(OP_DIV, a -> result, a, b);
        }
        else if(token == DIV)
        {
@@ -1453,28 +1536,28 @@ oberon_make_bin_op(oberon_context_t * ctx, int token, oberon_expr_t * a, oberon_
                        oberon_error(ctx, "operator DIV requires integer type");
                }
 
-               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
-               expr = oberon_new_operator(OP_DIV, result, a, b);
+               oberon_autocast_binary_op(ctx, &a, &b);
+               expr = oberon_new_operator(OP_DIV, a -> result, a, b);
        }
        else
        {
-               oberon_autocast_binary_op(ctx, a -> result, b -> result, &result);
+               oberon_autocast_binary_op(ctx, &a, &b);
 
                if(token == PLUS)
                {
-                       expr = oberon_new_operator(OP_ADD, result, a, b);
+                       expr = oberon_new_operator(OP_ADD, a -> result, a, b);
                }
                else if(token == MINUS)
                {
-                       expr = oberon_new_operator(OP_SUB, result, a, b);
+                       expr = oberon_new_operator(OP_SUB, a -> result, a, b);
                }
                else if(token == STAR)
                {
-                       expr = oberon_new_operator(OP_MUL, result, a, b);
+                       expr = oberon_new_operator(OP_MUL, a -> result, a, b);
                }
                else if(token == MOD)
                {
-                       expr = oberon_new_operator(OP_MOD, result, a, b);
+                       expr = oberon_new_operator(OP_MOD, a -> result, a, b);
                }
                else
                {
@@ -1527,6 +1610,12 @@ oberon_simple_expr(oberon_context_t * ctx)
        }
 
        expr = oberon_term_expr(ctx);
+
+       if(minus)
+       {
+               expr = oberon_make_unary_op(ctx, MINUS, expr);
+       }
+
        while(ISADDOP(ctx -> token))
        {
                int token = ctx -> token;
@@ -1536,11 +1625,6 @@ oberon_simple_expr(oberon_context_t * ctx)
                expr = oberon_make_bin_op(ctx, token, expr, inter);
        }
 
-       if(minus)
-       {
-               expr = oberon_make_unary_op(ctx, MINUS, expr);
-       }
-
        return expr;
 }
 
@@ -1635,7 +1719,7 @@ oberon_def(oberon_context_t * ctx, int * export, int * read_only)
 }
 
 static oberon_object_t *
-oberon_ident_def(oberon_context_t * ctx, int class)
+oberon_ident_def(oberon_context_t * ctx, int class, bool check_upscope)
 {
        char * name;
        int export;
@@ -1645,19 +1729,19 @@ oberon_ident_def(oberon_context_t * ctx, int class)
        name = oberon_assert_ident(ctx);
        oberon_def(ctx, &export, &read_only);
 
-       x = oberon_define_object(ctx -> decl, name, class, export, read_only);
+       x = oberon_define_object(ctx -> decl, name, class, export, read_only, check_upscope);
        return x;
 }
 
 static void
-oberon_ident_list(oberon_context_t * ctx, int class, int * num, oberon_object_t ** list)
+oberon_ident_list(oberon_context_t * ctx, int class, bool check_upscope, int * num, oberon_object_t ** list)
 {
        *num = 1;
-       *list = oberon_ident_def(ctx, class);
+       *list = oberon_ident_def(ctx, class, check_upscope);
        while(ctx -> token == COMMA)
        {
                oberon_assert_token(ctx, COMMA);
-               oberon_ident_def(ctx, class);
+               oberon_ident_def(ctx, class, check_upscope);
                *num += 1;
        }
 }
@@ -1670,7 +1754,7 @@ oberon_var_decl(oberon_context_t * ctx)
        oberon_type_t * type;
        type = oberon_new_type_ptr(OBERON_TYPE_VOID);
 
-       oberon_ident_list(ctx, OBERON_CLASS_VAR, &num, &list);
+       oberon_ident_list(ctx, OBERON_CLASS_VAR, false, &num, &list);
        oberon_assert_token(ctx, COLON);
        oberon_type(ctx, &type);
 
@@ -1694,7 +1778,7 @@ oberon_fp_section(oberon_context_t * ctx, int * num_decl)
 
        int num;
        oberon_object_t * list;
-       oberon_ident_list(ctx, class, &num, &list);
+       oberon_ident_list(ctx, class, false, &num, &list);
 
        oberon_assert_token(ctx, COLON);
 
@@ -1811,7 +1895,7 @@ oberon_make_return(oberon_context_t * ctx, oberon_expr_t * expr)
                        oberon_error(ctx, "procedure requires expression on result");
                }
 
-               oberon_autocast_to(ctx, expr, result_type);
+               expr = oberon_autocast_to(ctx, expr, result_type);
        }
 
        proc -> has_return = 1;
@@ -1914,7 +1998,7 @@ oberon_proc_decl(oberon_context_t * ctx)
        }
        else
        {
-               proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, export, read_only);
+               proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, export, read_only, false);
                proc -> type = signature;
                proc -> scope = proc_scope;
                oberon_generator_init_proc(ctx, proc);
@@ -1935,7 +2019,7 @@ oberon_const_decl(oberon_context_t * ctx)
        oberon_item_t * value;
        oberon_object_t * constant;
 
-       constant = oberon_ident_def(ctx, OBERON_CLASS_CONST);
+       constant = oberon_ident_def(ctx, OBERON_CLASS_CONST, false);
        oberon_assert_token(ctx, EQUAL);
        value = oberon_const_expr(ctx);
        constant -> value = value;
@@ -1961,31 +2045,6 @@ oberon_make_array_type(oberon_context_t * ctx, oberon_expr_t * size, oberon_type
        arr -> base = base;
 }
 
-static void
-oberon_field_list(oberon_context_t * ctx, oberon_type_t * rec)
-{
-       if(ctx -> token == IDENT)
-       {
-               int num;
-               oberon_object_t * list;
-               oberon_type_t * type;
-               type = oberon_new_type_ptr(OBERON_TYPE_VOID);
-
-               oberon_ident_list(ctx, OBERON_CLASS_FIELD, &num, &list);
-               oberon_assert_token(ctx, COLON);
-               oberon_type(ctx, &type);
-
-               oberon_object_t * field = list;
-               for(int i = 0; i < num; i++)
-               {
-                       field -> type = type;
-                       field = field -> next;
-               }
-
-               rec -> num_decl += num;
-       }
-}
-
 static void
 oberon_qualident_type(oberon_context_t * ctx, oberon_type_t ** type)
 {
@@ -2006,7 +2065,7 @@ oberon_qualident_type(oberon_context_t * ctx, oberon_type_t ** type)
        }
        else
        {
-               to = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, 0, 0);
+               to = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, false, false, false);
                to -> type = oberon_new_type_ptr(OBERON_TYPE_VOID);
        }
 
@@ -2044,6 +2103,87 @@ oberon_make_open_array(oberon_context_t * ctx, oberon_type_t * base, oberon_type
        type -> base = base;
 }
 
+static void
+oberon_field_list(oberon_context_t * ctx, oberon_type_t * rec, oberon_scope_t * modscope)
+{
+       if(ctx -> token == IDENT)
+       {
+               int num;
+               oberon_object_t * list;
+               oberon_type_t * type;
+               type = oberon_new_type_ptr(OBERON_TYPE_VOID);
+
+               oberon_ident_list(ctx, OBERON_CLASS_FIELD, true, &num, &list);
+               oberon_assert_token(ctx, COLON);
+
+               oberon_scope_t * current = ctx -> decl;
+               ctx -> decl = modscope;
+               oberon_type(ctx, &type);
+               ctx -> decl = current;
+
+               oberon_object_t * field = list;
+               for(int i = 0; i < num; i++)
+               {
+                       field -> type = type;
+                       field = field -> next;
+               }
+
+               rec -> num_decl += num;
+       }
+}
+
+static void
+oberon_type_record_body(oberon_context_t * ctx, oberon_type_t * rec)
+{
+       oberon_scope_t * modscope = ctx -> mod -> decl; 
+       oberon_scope_t * oldscope = ctx -> decl;
+       ctx -> decl = modscope;
+
+       if(ctx -> token == LPAREN)
+       {
+               oberon_assert_token(ctx, LPAREN);
+
+               oberon_object_t * typeobj;
+               typeobj = oberon_qualident(ctx, NULL, true);
+
+               if(typeobj -> class != OBERON_CLASS_TYPE)
+               {
+                       oberon_error(ctx, "base must be type");
+               }
+
+               if(typeobj -> type -> class != OBERON_TYPE_RECORD)
+               {
+                       oberon_error(ctx, "base must be record type");
+               }
+
+               rec -> base = typeobj -> type;
+               ctx -> decl = rec -> base -> scope;
+
+               oberon_assert_token(ctx, RPAREN);
+       }
+       else
+       {
+               ctx -> decl = NULL;
+       }
+
+       oberon_scope_t * this_scope;
+       this_scope = oberon_open_scope(ctx);
+       this_scope -> local = true;
+       this_scope -> parent = NULL;
+       this_scope -> parent_type = rec;
+
+       oberon_field_list(ctx, rec, modscope);
+       while(ctx -> token == SEMICOLON)
+       {
+               oberon_assert_token(ctx, SEMICOLON);
+               oberon_field_list(ctx, rec, modscope);
+       }
+
+       rec -> scope = this_scope;
+       rec -> decl = this_scope -> list -> next;
+       ctx -> decl = oldscope;
+}
+
 static void
 oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
 {
@@ -2085,24 +2225,10 @@ oberon_type(oberon_context_t * ctx, oberon_type_t ** type)
                rec -> class = OBERON_TYPE_RECORD;
                rec -> module = ctx -> mod;
 
-               oberon_scope_t * record_scope;
-               record_scope = oberon_open_scope(ctx);
-               // TODO parent object
-               //record_scope -> parent = NULL;
-               record_scope -> local = 1;
-
                oberon_assert_token(ctx, RECORD);
-               oberon_field_list(ctx, rec);
-               while(ctx -> token == SEMICOLON)
-               {
-                       oberon_assert_token(ctx, SEMICOLON);
-                       oberon_field_list(ctx, rec);
-               }
+               oberon_type_record_body(ctx, rec);
                oberon_assert_token(ctx, END);
 
-               rec -> decl = record_scope -> list -> next;
-               oberon_close_scope(record_scope);
-
                *type = rec;
        }
        else if(ctx -> token == POINTER)
@@ -2147,7 +2273,7 @@ oberon_type_decl(oberon_context_t * ctx)
        newtype = oberon_find_object(ctx -> decl, name, 0);
        if(newtype == NULL)
        {
-               newtype = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, export, read_only);
+               newtype = oberon_define_object(ctx -> decl, name, OBERON_CLASS_TYPE, export, read_only, false);
                newtype -> type = oberon_new_type_ptr(OBERON_TYPE_VOID);
                assert(newtype -> type);
        }
@@ -2198,7 +2324,8 @@ oberon_prevent_recursive_pointer(oberon_context_t * ctx, oberon_type_t * type)
                oberon_error(ctx, "recursive pointer declaration");
        }
 
-       if(type -> base -> class == OBERON_TYPE_POINTER)
+       if(type -> class == OBERON_TYPE_POINTER
+               && type -> base -> class == OBERON_TYPE_POINTER)
        {
                oberon_error(ctx, "attempt to make pointer to pointer");
        }
@@ -2547,7 +2674,7 @@ oberon_assign(oberon_context_t * ctx, oberon_expr_t * src, oberon_expr_t * dst)
                oberon_error(ctx, "read-only destination");
        }
 
-       oberon_autocast_to(ctx, src, dst -> result);
+       src = oberon_autocast_to(ctx, src, dst -> result);
        oberon_generate_assign(ctx, src, dst);
 }
 
@@ -2626,7 +2753,7 @@ oberon_import_module(oberon_context_t * ctx, char * alias, char * name)
        }
 
        oberon_object_t * ident;
-       ident = oberon_define_object(ctx -> decl, alias, OBERON_CLASS_MODULE, 0, 0);
+       ident = oberon_define_object(ctx -> decl, alias, OBERON_CLASS_MODULE, false, false, false);
        ident -> module = m;
 }
 
@@ -2698,6 +2825,8 @@ oberon_parse_module(oberon_context_t * ctx)
        {
                oberon_error(ctx, "module name not matched");
        }
+
+       oberon_generator_fini_module(ctx -> mod);
 }
 
 // =======================================================================
@@ -2714,21 +2843,33 @@ register_default_types(oberon_context_t * ctx)
        ctx -> void_ptr_type -> base = ctx -> void_type;
        oberon_generator_init_type(ctx, ctx -> void_ptr_type);
 
-       ctx -> int_type = oberon_new_type_integer(sizeof(int));
+       ctx -> bool_type = oberon_new_type_boolean();
+       oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+
+       ctx -> byte_type = oberon_new_type_integer(1);
+       oberon_define_type(ctx -> world_scope, "BYTE", ctx -> byte_type, 1);
+
+       ctx -> shortint_type = oberon_new_type_integer(2);
+       oberon_define_type(ctx -> world_scope, "SHORTINT", ctx -> shortint_type, 1);
+
+       ctx -> int_type = oberon_new_type_integer(4);
        oberon_define_type(ctx -> world_scope, "INTEGER", ctx -> int_type, 1);
 
-       ctx -> bool_type = oberon_new_type_boolean(sizeof(bool));
-       oberon_define_type(ctx -> world_scope, "BOOLEAN", ctx -> bool_type, 1);
+       ctx -> longint_type = oberon_new_type_integer(8);
+       oberon_define_type(ctx -> world_scope, "LONGINT", ctx -> longint_type, 1);
 
-       ctx -> real_type = oberon_new_type_real(sizeof(float));
+       ctx -> real_type = oberon_new_type_real(4);
        oberon_define_type(ctx -> world_scope, "REAL", ctx -> real_type, 1);
+
+       ctx -> longreal_type = oberon_new_type_real(8);
+       oberon_define_type(ctx -> world_scope, "LONGREAL", ctx -> longreal_type, 1);
 }
 
 static void
 oberon_new_intrinsic(oberon_context_t * ctx, char * name, GenerateFuncCallback f, GenerateProcCallback p)
 {
        oberon_object_t * proc;
-       proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, 1, 0);
+       proc = oberon_define_object(ctx -> decl, name, OBERON_CLASS_PROC, true, false, false);
        proc -> sysproc = 1;
        proc -> genfunc = f;
        proc -> genproc = p;
@@ -2882,6 +3023,8 @@ oberon_compile_module(oberon_context_t * ctx, const char * newcode)
        int token = ctx -> token;
        char * string = ctx -> string;
        int integer = ctx -> integer;
+       int real = ctx -> real;
+       bool longmode = ctx -> longmode;
        oberon_scope_t * decl = ctx -> decl;
        oberon_module_t * mod = ctx -> mod;
 
@@ -2907,6 +3050,8 @@ oberon_compile_module(oberon_context_t * ctx, const char * newcode)
        ctx -> token = token;
        ctx -> string = string;
        ctx -> integer = integer;
+       ctx -> real = real;
+       ctx -> longmode = longmode;
        ctx -> decl = decl;
        ctx -> mod = mod;