GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/compile.c Lines: 83 86 96.5 %
Date: 2020-09-14 20:46:08 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
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 Gwion gwion, 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
  if(c->ast)
56
620
    ast_cleaner(gwion, c->ast);
57
1335
}
58
59
1335
ANN static m_bool _compiler_open(struct Compiler* c) {
60
1335
  if(c->type == COMPILE_NAME) {
61
1333
    m_str name = c->name;
62
1333
    c->name = realpath(name, NULL);
63
1333
    xfree(name);
64
1333
    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
1335
ANN static inline m_bool compiler_open(MemPool p, struct Compiler* c) {
88
1335
  char name[strlen(c->name) + 1];
89
1335
  strcpy(name, c->name);
90
#ifndef __FUZZING__
91

1335
  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
1335
  if(_compiler_open(c) < 0) {
97
696
    compiler_error(p, c);
98
696
    gw_err(_("can't open '%s'\n"), name);
99
696
    return GW_ERROR;
100
  }
101
639
  return GW_OK;
102
}
103
104
639
ANN static inline m_bool _check(struct Gwion_* gwion, struct Compiler* c) {
105
639
  struct AstGetter_ arg = { c->name, c->file, gwion->st, .ppa=gwion->ppa };
106
639
  CHECK_OB((c->ast = parse(&arg)))
107
620
  gwion->env->name = c->name;
108
1436
  for(m_uint i = 0; i < vector_size(&gwion->data->passes->vec); ++i) {
109
1030
    const compilation_pass pass = (compilation_pass)vector_at(&gwion->data->passes->vec, i);
110
1030
    CHECK_BB(pass(gwion->env, c->ast))
111
  }
112
406
  return GW_OK;
113
}
114
115
1335
ANN static m_uint _compile(struct Gwion_* gwion, struct Compiler* c) {
116
//  CHECK_BB(compiler_open(gwion->mp, c))
117
1335
  if(compiler_open(gwion->mp, c) < 0)
118
696
    return 0;
119
639
  if(_check(gwion, c) < 0) {
120
233
    gw_err(_("while compiling file '%s'\n"), c->base);
121
233
    return 0;
122
  }
123
406
  if(gwion->emit->info->code) {
124
406
    const VM_Shred shred = new_vm_shred(gwion->mp, gwion->emit->info->code);
125
406
    shred->info->args = c->args;
126
406
    vm_add_shred(gwion->vm, shred);
127
406
    gwion->emit->info->code = NULL;
128
406
    return shred->tick->xid;
129
  }
130
  return GW_OK;
131
}
132
133
1335
ANN static m_uint compile(struct Gwion_* gwion, struct Compiler* c) {
134
1335
  compiler_name(gwion->mp, c);
135
1335
  MUTEX_LOCK(gwion->data->mutex);
136
1335
  const m_uint ret = _compile(gwion, c);
137
1335
  MUTEX_UNLOCK(gwion->data->mutex);
138
1335
  compiler_clean(gwion, c);
139
1335
  return ret;
140
}
141
142
1333
ANN m_uint compile_filename(struct Gwion_* gwion, const m_str filename) {
143
1333
  struct Compiler c = { .base=filename, .type=COMPILE_NAME };
144
1333
  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
}