GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/compile.c Lines: 83 86 96.5 %
Date: 2020-09-14 00:22:58 Branches: 41 46 89.1 %

Line Branch Exec Source
1
#include "gwion_util.h"
2
#include "gwion_ast.h"
3
#include "gwion_env.h"
4
#include "vm.h"
5
#include "instr.h"
6
#include "emit.h"
7
#include "compile.h"
8
#include "gwion.h"
9
#include "pass.h"
10
#include "clean.h"
11
12
enum compile_type {
13
  COMPILE_NAME,
14
  COMPILE_MSTR,
15
  COMPILE_FILE
16
};
17
18
struct Compiler {
19
  const m_str base;
20
  m_str  name;
21
  m_str data;
22
  FILE*  file;
23
  Ast    ast;
24
  Vector args;
25
  enum compile_type type;
26
};
27
28
1333
ANN static void compiler_name(MemPool p, struct Compiler* c) {
29
1333
  m_str d = strdup(c->base);
30
1333
  c->name = strsep(&d, ":");
31
1333
  if(d)
32
2
    c->args = new_vector(p);
33
2668
  while(d)
34
2
    vector_add(c->args, (vtype)strdup(strsep(&d, ":")));
35
1333
  free(d);
36
1333
}
37
38
695
ANN static inline void compiler_error(MemPool p, const struct Compiler* c) {
39
695
  if(c->args) {
40
2
    for(m_uint i = 0; i < vector_size(c->args); ++i) {
41
1
      const m_str str = (m_str)vector_at(c->args, i);
42
1
      if(str)
43
1
        xfree((m_str)vector_at(c->args, i));
44
    }
45
1
    free_vector(p, c->args);
46
  }
47
695
}
48
49
1333
ANN static void compiler_clean(const Gwion gwion, const struct Compiler* c) {
50
1333
  if(c->name)
51
638
    xfree(c->name);
52
  /* test c->type because COMPILE_FILE does not own file */
53

1333
  if(c->type != COMPILE_FILE && c->file)
54
637
    fclose(c->file);
55
1333
  if(c->ast)
56
619
    ast_cleaner(gwion, c->ast);
57
1333
}
58
59
1333
ANN static m_bool _compiler_open(struct Compiler* c) {
60
1333
  if(c->type == COMPILE_NAME) {
61
1331
    m_str name = c->name;
62
1331
    c->name = realpath(name, NULL);
63
1331
    xfree(name);
64
1331
    return c->name ? !!(c->file = fopen(c->name, "r")) : GW_ERROR;
65
2
  } else if(c->type == COMPILE_MSTR) {
66
1
    c->file = c->data ? fmemopen(c->data, strlen(c->data), "r") : NULL;
67
1
    return c->file ? GW_OK : GW_ERROR;
68
  }
69
1
  return GW_OK;
70
}
71
72
#ifndef BUILD_ON_WINDOWS
73
#include <sys/stat.h>
74
1
ANN static int is_reg(const m_str path) {
75
  struct stat s;
76
1
  stat(path, &s);
77
1
  return S_ISREG(s.st_mode);
78
}
79
#else
80
ANN static m_bool is_reg(const m_str path) {
81
  const DWORD dw = GetFileAttributes(path);
82
  return !(dw == INVALID_FILE_ATTRIBUTES ||
83
           dw & FILE_ATTRIBUTE_DIRECTORY);
84
}
85
#endif
86
87
1333
ANN static inline m_bool compiler_open(MemPool p, struct Compiler* c) {
88
1333
  char name[strlen(c->name) + 1];
89
1333
  strcpy(name, c->name);
90
#ifndef __FUZZING__
91

1333
  if(c->type == COMPILE_FILE && !is_reg(name)) {
92
    gw_err(_("'%s': is a not a regular file\n"), name);
93
    return GW_ERROR;
94
  }
95
#endif
96
1333
  if(_compiler_open(c) < 0) {
97
695
    compiler_error(p, c);
98
695
    gw_err(_("can't open '%s'\n"), name);
99
695
    return GW_ERROR;
100
  }
101
638
  return GW_OK;
102
}
103
104
638
ANN static inline m_bool _check(struct Gwion_* gwion, struct Compiler* c) {
105
638
  struct AstGetter_ arg = { c->name, c->file, gwion->st, .ppa=gwion->ppa };
106
638
  CHECK_OB((c->ast = parse(&arg)))
107
619
  gwion->env->name = c->name;
108
1433
  for(m_uint i = 0; i < vector_size(&gwion->data->passes->vec); ++i) {
109
1028
    const compilation_pass pass = (compilation_pass)vector_at(&gwion->data->passes->vec, i);
110
1028
    CHECK_BB(pass(gwion->env, c->ast))
111
  }
112
405
  return GW_OK;
113
}
114
115
1333
ANN static m_uint _compile(struct Gwion_* gwion, struct Compiler* c) {
116
//  CHECK_BB(compiler_open(gwion->mp, c))
117
1333
  if(compiler_open(gwion->mp, c) < 0)
118
695
    return 0;
119
638
  if(_check(gwion, c) < 0) {
120
233
    gw_err(_("while compiling file '%s'\n"), c->base);
121
233
    return 0;
122
  }
123
405
  if(gwion->emit->info->code) {
124
405
    const VM_Shred shred = new_vm_shred(gwion->mp, gwion->emit->info->code);
125
405
    shred->info->args = c->args;
126
405
    vm_add_shred(gwion->vm, shred);
127
405
    gwion->emit->info->code = NULL;
128
405
    return shred->tick->xid;
129
  }
130
  return GW_OK;
131
}
132
133
1333
ANN static m_uint compile(struct Gwion_* gwion, struct Compiler* c) {
134
1333
  compiler_name(gwion->mp, c);
135
1333
  MUTEX_LOCK(gwion->data->mutex);
136
1333
  const m_uint ret = _compile(gwion, c);
137
1333
  MUTEX_UNLOCK(gwion->data->mutex);
138
1333
  compiler_clean(gwion, c);
139
1333
  return ret;
140
}
141
142
1331
ANN m_uint compile_filename(struct Gwion_* gwion, const m_str filename) {
143
1331
  struct Compiler c = { .base=filename, .type=COMPILE_NAME };
144
1331
  return compile(gwion, &c);
145
}
146
147
1
ANN m_uint compile_string(struct Gwion_* gwion, const m_str filename, const m_str data) {
148
1
  struct Compiler c = { .base=filename, .type=COMPILE_MSTR, .data=data };
149
1
  return compile(gwion, &c);
150
}
151
152
1
ANN m_uint compile_file(struct Gwion_* gwion, const m_str filename, FILE* file) {
153
1
  struct Compiler c = { .base=filename, .type=COMPILE_FILE, .file=file };
154
1
  return compile(gwion, &c);
155
}