1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <idlc.hxx>
21 #include <errorhandler.hxx>
22 #include <astscope.hxx>
23 #include <astmodule.hxx>
24 #include <astservice.hxx>
25 #include <astconstants.hxx>
26 #include <astexception.hxx>
27 #include <astenum.hxx>
28 #include <astinterface.hxx>
29 #include <astoperation.hxx>
30 #include <astbasetype.hxx>
31 #include <astdeclaration.hxx>
32 #include <astparameter.hxx>
33 #include <astsequence.hxx>
34 #include <asttype.hxx>
35 #include <asttypedef.hxx>
36 
37 #include <osl/diagnose.h>
38 #include <osl/file.hxx>
39 #include <osl/thread.h>
40 
41 #include <algorithm>
42 
scopeAsDecl(AstScope * pScope)43 AstDeclaration* scopeAsDecl(AstScope* pScope)
44 {
45     if (pScope == nullptr) return nullptr;
46 
47     switch( pScope->getScopeNodeType() )
48     {
49         case NT_service:
50         case NT_singleton:
51             return static_cast<AstService*>(pScope);
52         case NT_module:
53         case NT_root:
54             return static_cast<AstModule*>(pScope);
55         case NT_constants:
56             return static_cast<AstConstants*>(pScope);
57         case NT_interface:
58             return static_cast<AstInterface*>(pScope);
59         case NT_operation:
60             return static_cast<AstOperation*>(pScope);
61         case NT_exception:
62             return static_cast<AstException*>(pScope);
63         case NT_struct:
64             return static_cast<AstStruct*>(pScope);
65         case NT_enum:
66             return static_cast<AstEnum*>(pScope);
67         default:
68             return nullptr;
69     }
70 }
71 
declAsScope(AstDeclaration * pDecl)72 AstScope* declAsScope(AstDeclaration* pDecl)
73 {
74     if (pDecl == nullptr) return nullptr;
75 
76     switch(pDecl->getNodeType())
77     {
78         case NT_interface:
79             return static_cast<AstInterface*>(pDecl);
80         case NT_service:
81         case NT_singleton:
82             return static_cast<AstService*>(pDecl);
83         case NT_module:
84         case NT_root:
85             return static_cast<AstModule*>(pDecl);
86         case NT_constants:
87             return static_cast<AstConstants*>(pDecl);
88         case NT_exception:
89             return static_cast<AstException*>(pDecl);
90         case NT_struct:
91             return static_cast<AstStruct*>(pDecl);
92         case NT_enum:
93             return static_cast<AstEnum*>(pDecl);
94         case NT_operation:
95             return static_cast<AstOperation*>(pDecl);
96         default:
97             return nullptr;
98    }
99 }
100 
predefineXInterface(AstModule * pRoot)101 static void predefineXInterface(AstModule* pRoot)
102 {
103     // define the modules  com::sun::star::uno
104     AstModule* pParentScope = pRoot;
105     AstModule* pModule = new AstModule("com", pParentScope);
106     pModule->setPredefined(true);
107     pParentScope->addDeclaration(pModule);
108     pParentScope = pModule;
109     pModule = new AstModule("sun", pParentScope);
110     pModule->setPredefined(true);
111     pParentScope->addDeclaration(pModule);
112     pParentScope = pModule;
113     pModule = new AstModule("star", pParentScope);
114     pModule->setPredefined(true);
115     pParentScope->addDeclaration(pModule);
116     pParentScope = pModule;
117     pModule = new AstModule("uno", pParentScope);
118     pModule->setPredefined(true);
119     pParentScope->addDeclaration(pModule);
120     pParentScope = pModule;
121 
122     // define XInterface
123     AstInterface* pInterface = new AstInterface("XInterface", nullptr, pParentScope);
124     pInterface->setDefined();
125     pInterface->setPredefined(true);
126     pInterface->setPublished();
127     pParentScope->addDeclaration(pInterface);
128 
129     // define XInterface::queryInterface
130     AstOperation* pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_any)),
131                                          "queryInterface", pInterface);
132     AstParameter* pParam = new AstParameter(DIR_IN, false,
133                                             static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_type)),
134                                             "aType", pOp);
135     pOp->addDeclaration(pParam);
136     pInterface->addMember(pOp);
137 
138     // define XInterface::acquire
139     pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_void)),
140                            "acquire", pInterface);
141     pInterface->addMember(pOp);
142 
143     // define XInterface::release
144     pOp = new AstOperation(static_cast<AstType*>(pRoot->lookupPrimitiveType(ET_void)),
145                            "release", pInterface);
146     pInterface->addMember(pOp);
147 }
148 
initializePredefinedTypes(AstModule * pRoot)149 static void initializePredefinedTypes(AstModule* pRoot)
150 {
151     if ( pRoot )
152     {
153          AstBaseType* pPredefined = new AstBaseType(ET_long, "long", pRoot);
154          pRoot->addDeclaration(pPredefined);
155 
156          pPredefined = new AstBaseType(ET_ulong, "unsigned long", pRoot);
157          pRoot->addDeclaration(pPredefined);
158 
159          pPredefined = new AstBaseType(ET_hyper, "hyper", pRoot);
160          pRoot->addDeclaration(pPredefined);
161 
162          pPredefined = new AstBaseType(ET_uhyper, "unsigned hyper", pRoot);
163          pRoot->addDeclaration(pPredefined);
164 
165          pPredefined = new AstBaseType(ET_short, "short", pRoot);
166          pRoot->addDeclaration(pPredefined);
167 
168          pPredefined = new AstBaseType(ET_ushort, "unsigned short", pRoot);
169          pRoot->addDeclaration(pPredefined);
170 
171          pPredefined = new AstBaseType(ET_float, "float", pRoot);
172          pRoot->addDeclaration(pPredefined);
173 
174          pPredefined = new AstBaseType(ET_double, "double", pRoot);
175          pRoot->addDeclaration(pPredefined);
176 
177          pPredefined = new AstBaseType(ET_char, "char", pRoot);
178          pRoot->addDeclaration(pPredefined);
179 
180          pPredefined = new AstBaseType(ET_byte, "byte", pRoot);
181          pRoot->addDeclaration(pPredefined);
182 
183          pPredefined = new AstBaseType(ET_any, "any", pRoot);
184          pRoot->addDeclaration(pPredefined);
185 
186          pPredefined = new AstBaseType(ET_string, "string", pRoot);
187          pRoot->addDeclaration(pPredefined);
188 
189          pPredefined = new AstBaseType(ET_type, "type", pRoot);
190          pRoot->addDeclaration(pPredefined);
191 
192          pPredefined = new AstBaseType(ET_boolean, "boolean", pRoot);
193          pRoot->addDeclaration(pPredefined);
194 
195          pPredefined = new AstBaseType(ET_void, "void", pRoot);
196          pRoot->addDeclaration(pPredefined);
197     }
198 }
199 
Idlc(Options * pOptions)200 Idlc::Idlc(Options* pOptions)
201     : m_pOptions(pOptions)
202     , m_bIsDocValid(false)
203     , m_bIsInMainfile(true)
204     , m_published(false)
205     , m_errorCount(0)
206     , m_warningCount(0)
207     , m_lineNumber(0)
208     , m_offsetStart(0)
209     , m_offsetEnd(0)
210     , m_parseState(PS_NoState)
211 {
212     m_pScopes.reset( new AstStack() );
213     // init root object after construction
214     m_pRoot = nullptr;
215     m_bGenerateDoc = m_pOptions->isValid("-C");
216 }
217 
~Idlc()218 Idlc::~Idlc()
219 {
220 }
221 
init()222 void Idlc::init()
223 {
224     m_pRoot.reset(new AstModule(NT_root, OString(), nullptr));
225 
226     // push the root node on the stack
227     m_pScopes->push(m_pRoot.get());
228     initializePredefinedTypes(m_pRoot.get());
229     predefineXInterface(m_pRoot.get());
230 }
231 
reset()232 void Idlc::reset()
233 {
234     m_bIsDocValid = false;
235     m_bIsInMainfile = true;
236     m_published = false;
237 
238     m_errorCount = 0;
239     m_warningCount = 0;
240     m_lineNumber = 0;
241     m_parseState = PS_NoState;
242 
243     m_fileName.clear();
244     m_mainFileName.clear();
245     m_realFileName.clear();
246     m_documentation.clear();
247 
248     m_pScopes->clear();
249     m_pRoot.reset( new AstModule(NT_root, OString(), nullptr) );
250 
251     // push the root node on the stack
252     m_pScopes->push(m_pRoot.get());
253     initializePredefinedTypes(m_pRoot.get());
254 
255     m_includes.clear();
256 }
257 
processDocumentation()258 OUString Idlc::processDocumentation()
259 {
260     OUString doc;
261     if (m_bIsDocValid) {
262         OString raw(getDocumentation());
263         if (m_bGenerateDoc) {
264             doc = OStringToOUString(raw, RTL_TEXTENCODING_UTF8);
265         } else if (raw.indexOf("@deprecated") != -1) {
266             //TODO: this check is somewhat crude
267             doc = "@deprecated";
268         }
269     }
270     return doc;
271 }
272 
lcl_writeString(::osl::File & rFile,::osl::FileBase::RC & o_rRC,OString const & rString)273 static void lcl_writeString(::osl::File & rFile, ::osl::FileBase::RC & o_rRC,
274         OString const& rString)
275 {
276     sal_uInt64 nWritten(0);
277     if (::osl::FileBase::E_None == o_rRC) {
278         o_rRC = rFile.write(rString.getStr(), rString.getLength(), nWritten);
279         if (static_cast<sal_uInt64>(rString.getLength()) != nWritten) {
280             o_rRC = ::osl::FileBase::E_INVAL; //?
281         }
282     }
283 }
284 
285 struct WriteDep
286 {
287     ::osl::File& m_rFile;
288     ::osl::FileBase::RC & m_rRC;
WriteDepWriteDep289     explicit WriteDep(::osl::File & rFile, ::osl::FileBase::RC & rRC)
290         : m_rFile(rFile), m_rRC(rRC) { }
operator ()WriteDep291     void operator() (OString const& rEntry)
292     {
293         lcl_writeString(m_rFile, m_rRC, " \\\n ");
294         lcl_writeString(m_rFile, m_rRC, rEntry);
295     }
296 };
297 
298 // write a dummy target for one included file, so the incremental build does
299 // not break with "No rule to make target" if the included file is removed
300 struct WriteDummy
301 {
302     ::osl::File& m_rFile;
303     ::osl::FileBase::RC & m_rRC;
WriteDummyWriteDummy304     explicit WriteDummy(::osl::File & rFile, ::osl::FileBase::RC & rRC)
305         : m_rFile(rFile), m_rRC(rRC) { }
operator ()WriteDummy306     void operator() (OString const& rEntry)
307     {
308         lcl_writeString(m_rFile, m_rRC, rEntry);
309         lcl_writeString(m_rFile, m_rRC, ":\n\n");
310     }
311 };
312 
313 bool
dumpDeps(OString const & rDepFile,OString const & rTarget)314 Idlc::dumpDeps(OString const& rDepFile, OString const& rTarget)
315 {
316     ::osl::File depFile(
317             OStringToOUString(rDepFile, osl_getThreadTextEncoding()));
318     ::osl::FileBase::RC rc =
319         depFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create);
320     if (::osl::FileBase::E_None != rc) {
321         return false;
322     }
323     lcl_writeString(depFile, rc, rTarget);
324     if (::osl::FileBase::E_None != rc) {
325         return false;
326     }
327     lcl_writeString(depFile, rc, " :");
328     if (::osl::FileBase::E_None != rc) {
329         return false;
330     }
331     m_includes.erase(getRealFileName()); // eeek, that is a temp file...
332     ::std::for_each(m_includes.begin(), m_includes.end(),
333             WriteDep(depFile, rc));
334     lcl_writeString(depFile, rc, "\n\n");
335     ::std::for_each(m_includes.begin(), m_includes.end(),
336             WriteDummy(depFile, rc));
337     if (::osl::FileBase::E_None != rc) {
338         return false;
339     }
340     rc = depFile.close();
341     return ::osl::FileBase::E_None == rc;
342 }
343 
344 static Idlc* pStaticIdlc = nullptr;
345 
idlc()346 Idlc* idlc()
347 {
348     return pStaticIdlc;
349 }
350 
setIdlc(Options * pOptions)351 Idlc* setIdlc(Options* pOptions)
352 {
353     delete pStaticIdlc;
354     pStaticIdlc = new Idlc(pOptions);
355     pStaticIdlc->init();
356     return pStaticIdlc;
357 }
358 
resolveTypedefs(AstDeclaration const * type)359 AstDeclaration const * resolveTypedefs(AstDeclaration const * type) {
360     if (type != nullptr) {
361         while (type->getNodeType() == NT_typedef) {
362             type = static_cast< AstTypeDef const * >(type)->getBaseType();
363         }
364     }
365     return type;
366 }
367 
deconstructAndResolveTypedefs(AstDeclaration const * type,sal_Int32 * rank)368 AstDeclaration const * deconstructAndResolveTypedefs(
369     AstDeclaration const * type, sal_Int32 * rank)
370 {
371     *rank = 0;
372     for (;;) {
373         if (type == nullptr) {
374             return nullptr;
375         }
376         switch (type->getNodeType()) {
377         case NT_typedef:
378             type = static_cast< AstTypeDef const * >(type)->getBaseType();
379             break;
380         case NT_sequence:
381             ++(*rank);
382             type = static_cast< AstSequence const * >(type)->getMemberType();
383             break;
384         default:
385             return type;
386         }
387     }
388 }
389 
resolveInterfaceTypedefs(AstType const * type)390 AstInterface const * resolveInterfaceTypedefs(AstType const * type) {
391     AstDeclaration const * decl = resolveTypedefs(type);
392     OSL_ASSERT(decl->getNodeType() == NT_interface);
393     return static_cast< AstInterface const * >(decl);
394 }
395 
396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
397