GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/compile.c Lines: 87 90 96.7 %
Date: 2020-09-21 18:02:52 Branches: 46 54 85.2 %

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
1335
ANN static void compiler_name(MemPool p, struct Compiler* c) {
29
1335
  m_str d = strdup(c->base);
30
1335
  c->name = strsep(&d, ":");
31
1335
  if(d)
32
2
    c->args = new_vector(p);
33
2672
  while(d)
34
2
    vector_add(c->args, (vtype)strdup(strsep(&d, ":")));
35
1335
  free(d);
36
1335
}
37
38
696
ANN static inline void compiler_error(MemPool p, const struct Compiler* c) {
39
696
  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
696
}
48
49
1335
ANN static void compiler_clean(const struct Compiler* c) {
50
1335
  if(c->name)
51
639
    xfree(c->name);
52
  /* test c->type because COMPILE_FILE does not own file */
53

1335
  if(c->type != COMPILE_FILE && c->file)
54
638
    fclose(c->file);
55
1335
}
56
57
1335
ANN static m_bool _compiler_open(struct Compiler* c) {
58
1335
  if(c->type == COMPILE_NAME) {
59
1333
    m_str name = c->name;
60
1333
    c->name = realpath(name, NULL);
61
1333
    xfree(name);
62
1333
    return c->name ? !!(c->file = fopen(c->name, "r")) : GW_ERROR;
63
2
  } else if(c->type == COMPILE_MSTR) {
64
1
    c->file = c->data ? fmemopen(c->data, strlen(c->data), "r") : NULL;
65
1
    return c->file ? GW_OK : GW_ERROR;
66
  }
67
1
  return GW_OK;
68
}
69
70
#ifndef BUILD_ON_WINDOWS
71
#include <sys/stat.h>
72
1
ANN static int is_reg(const m_str path) {
73
  struct stat s;
74
1
  stat(path, &s);
75

1
  return S_ISREG(s.st_mode) || !S_ISFIFO(s.st_mode);
76
}
77
#else
78
ANN static m_bool is_reg(const m_str path) {
79
  const DWORD dw = GetFileAttributes(path);
80
  return !(dw == INVALID_FILE_ATTRIBUTES ||
81
           dw & FILE_ATTRIBUTE_DIRECTORY);
82
}
83
#endif
84
85
1335
ANN static inline m_bool compiler_open(MemPool p, struct Compiler* c) {
86
1335
  char name[strlen(c->name) + 1];
87
1335
  strcpy(name, c->name);
88
#ifndef __FUZZING__
89

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