aboutsummaryrefslogtreecommitdiffstats
path: root/3rdparty/python-console/modified/pyinterpreter.cc
blob: 99b8883e46d53ad6090ee978d9d61eac5eba6776 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**
python-console
Copyright (C) 2014  Alex Tsui

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include "pyinterpreter.h"
#include <Python.h>
#include <iostream>
#include <map>
#include <memory>
#include "pyredirector.h"

static PyThreadState *m_threadState = NULL;
static PyObject *glb = NULL;
static PyObject *loc = NULL;

static std::list<std::string> m_suggestions;

template <typename... Args> std::string string_format(const std::string &format, Args... args)
{
    size_t size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
    std::unique_ptr<char[]> buf(new char[size]);
    snprintf(buf.get(), size, format.c_str(), args...);
    return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}

std::string pyinterpreter_execute(const std::string &command, int *errorCode)
{
    PyEval_AcquireThread(m_threadState);
    *errorCode = 0;

    PyObject *py_result;
    PyObject *dum;
    std::string res;
    py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
    if (py_result == 0) {
        if (PyErr_Occurred()) {
            *errorCode = 1;
            PyErr_Print();
            res = redirector_take_output(m_threadState);
        }

        PyEval_ReleaseThread(m_threadState);
        return res;
    }
    dum = PyEval_EvalCode(py_result, glb, loc);
    Py_XDECREF(dum);
    Py_XDECREF(py_result);
    if (PyErr_Occurred()) {
        *errorCode = 1;
        PyErr_Print();
    }

    res = redirector_take_output(m_threadState);

    PyEval_ReleaseThread(m_threadState);
    return res;
}

const std::list<std::string> &pyinterpreter_suggest(const std::string &hint)
{
    PyEval_AcquireThread(m_threadState);
    m_suggestions.clear();
    int i = 0;
    std::string escaped;
    for (char c : hint) {
        if (c == '\'' || c == '\\')
            escaped += '\\';
        escaped += c;
    }
    std::string command = string_format("sys.completer.complete('%s', %d)\n", escaped.c_str(), i);
    std::string res;
    do {
        PyObject *py_result;
        PyObject *dum;
        py_result = Py_CompileString(command.c_str(), "<stdin>", Py_single_input);
        if (py_result == nullptr)
            break;
        dum = PyEval_EvalCode(py_result, glb, loc);
        if (dum == nullptr)
            break;
        Py_XDECREF(dum);
        Py_XDECREF(py_result);
        res = redirector_take_output(m_threadState);

        ++i;
        command = string_format("sys.completer.complete('%s', %d)\n", escaped.c_str(), i);
        if (res.size()) {
            // throw away the newline
            res = res.substr(1, res.size() - 3);
            m_suggestions.push_back(res);
        }
    } while (res.size());

    PyEval_ReleaseThread(m_threadState);
    return m_suggestions;
}

void pyinterpreter_preinit()
{
    m_suggestions.clear();
    inittab_redirector();
}

void pyinterpreter_initialize()
{
#if PY_VERSION_HEX < 0x03090000
    PyEval_InitThreads();
#endif
    m_threadState = PyEval_SaveThread();
    PyEval_AcquireThread(m_threadState);

    PyObject *module = PyImport_ImportModule("__main__");
    loc = glb = PyModule_GetDict(module);

    PyRun_SimpleString("import sys\n"
                       "import redirector\n"
                       "import tempfile\n"
                       "sys.path.insert(0, \".\")\n" // add current path
                       "sys.stdout = redirector.redirector()\n"
                       "sys.stdin = tempfile.TemporaryFile(mode='r')\n"
                       "sys.stderr = sys.stdout\n"
                       "import rlcompleter\n"
                       "sys.completer = rlcompleter.Completer()\n");

    PyEval_ReleaseThread(m_threadState);
}

void pyinterpreter_finalize()
{
    m_suggestions.clear();

    PyEval_RestoreThread(m_threadState);
}

void pyinterpreter_aquire()
{
    PyEval_AcquireThread(m_threadState);
}

void pyinterpreter_release()
{
    PyEval_ReleaseThread(m_threadState);
}

std::string pyinterpreter_execute_file(const char *python_file, int *errorCode)
{
    PyEval_AcquireThread(m_threadState);
    *errorCode = 0;
    std::string res;
    FILE *fp = fopen(python_file, "r");
    if (fp == NULL) {
        *errorCode = 1;
        res = "Fatal error: file not found " + std::string(python_file) + "\n";
        return res;
    }

    if (PyRun_SimpleFile(fp, python_file)==-1) {
        *errorCode = 1;
        PyErr_Print();
    }
    res = redirector_take_output(m_threadState);

    PyEval_ReleaseThread(m_threadState);
    return res;
}
an>); end if; end Parse_Count; function Psl_To_Vhdl (N : Node) return Iirs.Iir is use Iirs; Res : Iir; begin case Get_Kind (N) is when N_HDL_Expr => Res := Iirs.Iir (Get_HDL_Node (N)); Free_Node (N); return Res; when others => Error_Kind ("psl_to_vhdl", N); end case; end Psl_To_Vhdl; function Vhdl_To_Psl (N : Iirs.Iir) return Node is use Iirs; Res : Node; begin Res := Create_Node_Loc (N_HDL_Expr); if N /= Null_Iir then Set_Location (Res, Get_Location (N)); Set_HDL_Node (Res, Int32 (N)); end if; return Res; end Vhdl_To_Psl; function Parse_FL_Property (Prio : Priority) return Node; function Parse_Parenthesis_Boolean return Node; function Parse_Boolean (Parent_Prio : Priority) return Node; function Parse_Unary_Boolean return Node is begin return Vhdl_To_Psl (Parse.Parse_Expression); end Parse_Unary_Boolean; function Parse_Boolean_Rhs (Parent_Prio : Priority; Left : Node) return Node is Kind : Nkind; Prio : Priority; Res : Node; Tmp : Node; begin Res := Left; loop case Current_Token is when Tok_And => Kind := N_And_Bool; Prio := Prio_Seq_And; when Tok_Or => Kind := N_Or_Bool; Prio := Prio_Seq_Or; when others => return Res; end case; if Parent_Prio >= Prio then return Res; end if; Tmp := Create_Node_Loc (Kind); Scan; Set_Left (Tmp, Res); Res := Tmp; Tmp := Parse_Boolean (Prio); Set_Right (Res, Tmp); end loop; end Parse_Boolean_Rhs; function Parse_Boolean (Parent_Prio : Priority) return Node is begin return Parse_Boolean_Rhs (Parent_Prio, Parse_Unary_Boolean); end Parse_Boolean; function Parse_Psl_Boolean return PSL_Node is begin return Parse_Boolean (Prio_Lowest); end Parse_Psl_Boolean; function Parse_Parenthesis_Boolean return Node is Res : Node; begin if Current_Token /= Tok_Left_Paren then Error_Msg_Parse ("'(' expected before boolean expression"); return Null_Node; else Scan; Res := Parse_Psl_Boolean; if Current_Token = Tok_Right_Paren then Scan; else Error_Msg_Parse ("missing matching ')' for boolean expression"); end if; return Res; end if; end Parse_Parenthesis_Boolean; function Parse_SERE (Prio : Priority) return Node is Left, Res : Node; Kind : Nkind; Op_Prio : Priority; begin Left := Parse_Psl_Sequence; -- FIXME: allow boolean; loop case Current_Token is when Tok_Semi_Colon => Kind := N_Concat_SERE; Op_Prio := Prio_Seq_Concat; when Tok_Colon => Kind := N_Fusion_SERE; Op_Prio := Prio_Seq_Fusion; when Tok_Within => Kind := N_Within_SERE; Op_Prio := Prio_Seq_Within; when Tok_Ampersand => -- For non-length matching and, the operator is '&'. Kind := N_And_Seq; Op_Prio := Prio_Seq_And; when Tok_And_And => Kind := N_Match_And_Seq; Op_Prio := Prio_Seq_And; when Tok_Bar => Kind := N_Or_Seq; Op_Prio := Prio_Seq_Or; -- when Tok_Bar_Bar => -- Res := Create_Node_Loc (N_Or_Bool); -- Scan; -- Set_Left (Res, Left); -- Set_Right (Res, Parse_Boolean (Prio_Seq_Or)); -- return Res; when others => return Left; end case; if Prio >= Op_Prio then return Left; end if; Res := Create_Node_Loc (Kind); Scan; Set_Left (Res, Left); Set_Right (Res, Parse_SERE (Op_Prio)); Left := Res; end loop; end Parse_SERE; -- precond : '{' -- postcond: next token after '}' function Parse_Braced_SERE return Node is Res : Node; begin pragma Assert (Current_Token = Tok_Left_Curly); Res := Create_Node_Loc (N_Braced_SERE); -- Skip '{' Scan; Set_SERE (Res, Parse_SERE (Prio_Lowest)); if Current_Token /= Tok_Right_Curly then Error_Msg_Parse ("missing '}' after braced SERE"); else -- Skip '}' Scan; end if; return Res; end Parse_Braced_SERE; -- Parse [ Count ] ']' function Parse_Maybe_Count (Kind : Nkind; Seq : Node) return Node is N : Node; begin N := Create_Node_Loc (Kind); Set_Sequence (N, Seq); Scan; if Current_Token /= Tok_Right_Bracket then Parse_Count (N); end if; if Current_Token /= Tok_Right_Bracket then Error_Msg_Parse ("missing ']'"); else Scan; end if; return N; end Parse_Maybe_Count; procedure Parse_Bracket_Range (N : Node) is begin if Current_Token /= Tok_Left_Bracket then Error_Msg_Parse ("'[' expected"); else Scan; Set_Low_Bound (N, Parse_Number); if Current_Token /= Tok_To then Error_Msg_Parse ("'to' expected in range after left bound"); else Scan; Set_High_Bound (N, Parse_Number); end if; if Current_Token /= Tok_Right_Bracket then Error_Msg_Parse ("']' expected after range"); else Scan; end if; end if; end Parse_Bracket_Range; function Parse_Bracket_Number return Node is Res : Node; begin if Current_Token /= Tok_Left_Bracket then Error_Msg_Parse ("'[' expected"); return Null_Node; else Scan; Res := Parse_Number; if Current_Token /= Tok_Right_Bracket then Error_Msg_Parse ("']' expected after range"); else Scan; end if; return Res; end if; end Parse_Bracket_Number; function Parse_Psl_Sequence return Node is Res, N : Node; begin case Current_Token is when Tok_Left_Curly => Res := Parse_Braced_SERE; if Current_Token = Tok_Arobase then N := Create_Node_Loc (N_Clocked_SERE); Set_SERE (N, Res); -- Skip '@' Scan; Set_Boolean (N, Parse_Psl_Boolean); Res := N; end if; when Tok_Brack_Star => return Parse_Maybe_Count (N_Star_Repeat_Seq, Null_Node); when Tok_Left_Paren => Res := Parse_Parenthesis_Boolean; if Current_Token = Tok_Or or else Current_Token = Tok_And then Res := Parse_Boolean_Rhs (Prio_Lowest, Res); end if; when Tok_Brack_Plus_Brack => Res := Create_Node_Loc (N_Plus_Repeat_Seq); Scan; return Res; when others => -- Repeated_SERE Res := Parse_Unary_Boolean; end case; loop case Current_Token is when Tok_Brack_Star => Res := Parse_Maybe_Count (N_Star_Repeat_Seq, Res); when Tok_Brack_Plus_Brack => N := Create_Node_Loc (N_Plus_Repeat_Seq); Set_Sequence (N, Res); -- Skip '[+]' Scan; Res := N; when Tok_Brack_Arrow => Res := Parse_Maybe_Count (N_Goto_Repeat_Seq, Res); when Tok_Brack_Equal => N := Create_Node_Loc (N_Equal_Repeat_Seq); Set_Sequence (N, Res); -- Skip '[=' Scan; Parse_Count (N); if Current_Token /= Tok_Right_Bracket then Error_Msg_Parse ("missing ']'"); else Scan; end if; Res := N; when others => return Res; end case; end loop; end Parse_Psl_Sequence; -- precond: '(' -- postcond: next token function Parse_Parenthesis_FL_Property return Node is Res : Node; Loc : Location_Type; begin Loc := Get_Token_Location; if Current_Token /= Tok_Left_Paren then Error_Msg_Parse ("'(' expected around property"); return Parse_FL_Property (Prio_Lowest); else Scan; Res := Parse_FL_Property (Prio_Lowest); if Current_Token /= Tok_Right_Paren then Error_Msg_Parse ("missing matching ')' for '(' at line " & Image (Loc, False)); else Scan; end if; return Res; end if; end Parse_Parenthesis_FL_Property; -- Parse [ '!' ] '[' finite_Range ']' '(' FL_Property ')' function Parse_Range_Property (K : Nkind) return Node is Res : Node; begin Res := Create_Node_Loc (K); Set_Strong_Flag (Res, Scan_Exclam_Mark); Scan; Parse_Bracket_Range (Res); Set_Property (Res, Parse_Parenthesis_FL_Property); return Res; end Parse_Range_Property; -- Parse [ '!' ] '(' Boolean ')' '[' Range ']' '(' FL_Property ')' function Parse_Boolean_Range_Property (K : Nkind) return Node is Res : Node; begin Res := Create_Node_Loc (K); Set_Strong_Flag (Res, Scan_Exclam_Mark); Scan; Set_Boolean (Res, Parse_Parenthesis_Boolean); Parse_Bracket_Range (Res); Set_Property (Res, Parse_Parenthesis_FL_Property); return Res; end Parse_Boolean_Range_Property; function Parse_FL_Property_1 return Node is Res : Node; Tmp : Node; begin case Current_Token is when Tok_Always => Res := Create_Node_Loc (N_Always); Scan; Set_Property (Res, Parse_FL_Property (Prio_FL_Invariance)); when Tok_Never => Res := Create_Node_Loc (N_Never); Scan; Set_Property (Res, Parse_FL_Property (Prio_FL_Invariance)); when Tok_Eventually => Res := Create_Node_Loc (N_Eventually); if not Scan_Exclam_Mark then Error_Msg_Parse ("'eventually' must be followed by '!'"); end if; Scan; Set_Property (Res, Parse_FL_Property (Prio_FL_Occurence)); when Tok_Next => Res := Create_Node_Loc (N_Next); Scan; if Current_Token = Tok_Left_Bracket then Set_Number (Res, Parse_Bracket_Number); Set_Property (Res, Parse_Parenthesis_FL_Property); else Set_Property (Res, Parse_FL_Property (Prio_FL_Occurence)); end if; when Tok_Next_A => Res := Parse_Range_Property (N_Next_A); when Tok_Next_E => Res := Parse_Range_Property (N_Next_E); when Tok_Next_Event => Res := Create_Node_Loc (N_Next_Event); Scan; Set_Boolean (Res, Parse_Parenthesis_Boolean); if Current_Token = Tok_Left_Bracket then Set_Number (Res, Parse_Bracket_Number); end if; Set_Property (Res, Parse_Parenthesis_FL_Property); when Tok_Next_Event_A => Res := Parse_Boolean_Range_Property (N_Next_Event_A); when Tok_Next_Event_E => Res := Parse_Boolean_Range_Property (N_Next_Event_E); when Tok_Left_Paren => return Parse_Parenthesis_FL_Property; when Tok_Left_Curly => Res := Parse_Psl_Sequence; if Get_Kind (Res) = N_Braced_SERE and then Current_Token = Tok_Left_Paren then -- FIXME: must check that RES is really a sequence -- (and not a SERE). Tmp := Create_Node_Loc (N_Overlap_Imp_Seq); Set_Sequence (Tmp, Res); Set_Property (Tmp, Parse_Parenthesis_FL_Property); Res := Tmp; end if; when others => Res := Parse_Psl_Sequence; end case; return Res; end Parse_FL_Property_1; function Parse_St_Binary_FL_Property (K : Nkind; Left : Node) return Node is Res : Node; begin Res := Create_Node_Loc (K); Set_Strong_Flag (Res, Scan_Exclam_Mark); Set_Inclusive_Flag (Res, Scan_Underscore); Scan; Set_Left (Res, Left); Set_Right (Res, Parse_FL_Property (Prio_FL_Bounding)); return Res; end Parse_St_Binary_FL_Property; function Parse_Binary_FL_Property (K : Nkind; Left : Node; Prio : Priority) return Node is Res : Node; begin Res := Create_Node_Loc (K); Scan; Set_Left (Res, Left); Set_Right (Res, Parse_FL_Property (Prio)); return Res; end Parse_Binary_FL_Property; function Parse_FL_Property (Prio : Priority) return Node is Res : Node; N : Node; begin Res := Parse_FL_Property_1; loop case Current_Token is when Tok_Minus_Greater => if Prio > Prio_Bool_Imp then return Res; end if; N := Create_Node_Loc (N_Log_Imp_Prop); Set_Left (N, Res); Scan; Set_Right (N, Parse_FL_Property (Prio_Bool_Imp)); Res := N; when Tok_Bar_Arrow => if Prio > Prio_Seq_Imp then return Res; end if; N := Create_Node_Loc (N_Overlap_Imp_Seq); Set_Sequence (N, Res); Scan; Set_Property (N, Parse_FL_Property (Prio_Seq_Imp)); Res := N; when Tok_Bar_Double_Arrow => if Prio > Prio_Seq_Imp then return Res; end if; N := Create_Node_Loc (N_Imp_Seq); Set_Sequence (N, Res); Scan; Set_Property (N, Parse_FL_Property (Prio_Seq_Imp)); Res := N; when Tok_Abort => if Prio > Prio_FL_Abort then return Res; end if; N := Create_Node_Loc (N_Abort); Set_Property (N, Res); Scan; Set_Boolean (N, Parse_Boolean (Prio_Lowest)); -- Left associative. return N; when Tok_Exclam_Mark => N := Create_Node_Loc (N_Strong); Set_Property (N, Res); Scan; Res := N; when Tok_Until => if Prio > Prio_FL_Bounding then return Res; end if; Res := Parse_St_Binary_FL_Property (N_Until, Res); when Tok_Before => if Prio > Prio_FL_Bounding then return Res; end if; Res := Parse_St_Binary_FL_Property (N_Before, Res); when Tok_Or => if Prio > Prio_Seq_Or then return Res; end if; Res := Parse_Binary_FL_Property (N_Or_Prop, Res, Prio_Seq_Or); when Tok_And => if Prio > Prio_Seq_And then return Res; end if; Res := Parse_Binary_FL_Property (N_And_Prop, Res, Prio_Seq_And); when Token_Relational_Operator_Type => return Vhdl_To_Psl (Parse.Parse_Relation_Rhs (Psl_To_Vhdl (Res))); when Tok_Colon | Tok_Bar | Tok_Ampersand | Tok_And_And => Error_Msg_Parse ("SERE operator '" & Image (Current_Token) & "' is not allowed in property"); Scan; N := Parse_FL_Property (Prio_Lowest); return Res; when Tok_Arobase => if Prio > Prio_Clock_Event then return Res; end if; N := Create_Node_Loc (N_Clock_Event); Set_Property (N, Res); Scan; Set_Boolean (N, Parse_Boolean (Prio_Clock_Event)); Res := N; when others => return Res; end case; end loop; end Parse_FL_Property; function Parse_Psl_Property return PSL_Node is begin return Parse_FL_Property (Prio_Lowest); end Parse_Psl_Property; -- precond: identifier -- postcond: ';' -- -- 6.2.4.1 Property declaration -- -- Property_Declaration ::= -- PROPERTY psl_identifier [ ( Formal_Parameter_List ) ] DEF_SYM -- property ; function Parse_Psl_Declaration (Tok : Token_Type) return PSL_Node is Res : Node; Param : Node; Last_Param : Node; Pkind : Nkind; Kind : Nkind; begin case Tok is when Tok_Psl_Property => Kind := N_Property_Declaration; when Tok_Psl_Sequence => Kind := N_Sequence_Declaration; when Tok_Psl_Endpoint => Kind := N_Endpoint_Declaration; when others => raise Internal_Error; end case; Res := Create_Node_Loc (Kind); if Current_Token = Tok_Identifier then Set_Identifier (Res, Current_Identifier); Scan; end if; -- Formal parameter list. if Current_Token = Tok_Left_Paren then Last_Param := Null_Node; loop -- precond: '(' or ';'. Scan; case Current_Token is when Tok_Psl_Const => Pkind := N_Const_Parameter; when Tok_Psl_Boolean => Pkind := N_Boolean_Parameter; when Tok_Psl_Property => Pkind := N_Property_Parameter; when Tok_Psl_Sequence => Pkind := N_Sequence_Parameter; when others => Error_Msg_Parse ("parameter type expected"); end case; -- Formal parameters. loop -- precond: parameter_type or ',' Scan; Param := Create_Node_Loc (Pkind); if Current_Token /= Tok_Identifier then Error_Msg_Parse ("identifier for parameter expected"); else Set_Identifier (Param, Current_Identifier); end if; if Last_Param = Null_Node then Set_Parameter_List (Res, Param); else Set_Chain (Last_Param, Param); end if; Last_Param := Param; Scan; exit when Current_Token /= Tok_Comma; end loop; exit when Current_Token = Tok_Right_Paren; if Current_Token /= Tok_Semi_Colon then Error_Msg_Parse ("';' expected between formal parameter"); end if; end loop; Scan; end if; if Current_Token /= Tok_Is then Error_Msg_Parse ("'is' expected after identifier"); else -- Skip 'is'. Scan; end if; case Kind is when N_Property_Declaration => Set_Property (Res, Parse_Psl_Property); when N_Sequence_Declaration | N_Endpoint_Declaration => Set_Sequence (Res, Parse_Psl_Sequence); when others => raise Internal_Error; end case; return Res; end Parse_Psl_Declaration; function Is_Instantiated_Declaration (N : PSL_Node) return Boolean is begin return Get_Parameter_List (N) = Null_Node; end Is_Instantiated_Declaration; end Parse_Psl;